feat(google_drive): comment read (#1732)

This commit is contained in:
Shea Craig
2025-03-18 13:48:49 -04:00
committed by GitHub
parent 8664b05507
commit a2ce2b7460
+103 -52
View File
@@ -179,7 +179,11 @@ impl GoogleDriveRouter {
"properties": { "properties": {
"query": { "query": {
"type": "string", "type": "string",
"description": "Search query", "description": "String to search for in the file's name.",
},
"mimeType": {
"type": "string",
"description": "MIME type to constrain the search to.",
}, },
"corpora": { "corpora": {
"type": "string", "type": "string",
@@ -398,10 +402,10 @@ impl GoogleDriveRouter {
}), }),
); );
let list_comments_tool = Tool::new( let get_comments_tool = Tool::new(
"list_comments".to_string(), "get_comments".to_string(),
indoc! {r#" indoc! {r#"
List comments for a file in google drive by id, given an input file id. List comments for a file in google drive, or get one comment and all of its replies.
"#} "#}
.to_string(), .to_string(),
json!({ json!({
@@ -411,9 +415,13 @@ impl GoogleDriveRouter {
"type": "string", "type": "string",
"description": "Id of the file to list comments for.", "description": "Id of the file to list comments for.",
}, },
"commentId": {
"type": "string",
"description": "Optional ID of the single comment to read in full.",
},
"pageSize": { "pageSize": {
"type": "number", "type": "number",
"description": "How many items to return from the search query, default 10, max 100", "description": "How many items to return from the search query, default 20, max 100",
} }
}, },
"required": ["fileId"], "required": ["fileId"],
@@ -510,7 +518,7 @@ impl GoogleDriveRouter {
update_tool, update_tool,
update_file_tool, update_file_tool,
sheets_tool, sheets_tool,
list_comments_tool, get_comments_tool,
], ],
instructions, instructions,
drive, drive,
@@ -530,6 +538,8 @@ impl GoogleDriveRouter {
.replace('\\', "\\\\") .replace('\\', "\\\\")
.replace('\'', "\\'"); .replace('\'', "\\'");
let mime_type = params.get("mimeType").and_then(|q| q.as_str());
// extract corpora query parameter, validate options, or default to "user" // extract corpora query parameter, validate options, or default to "user"
let corpus = params let corpus = params
.get("corpora") .get("corpora")
@@ -566,12 +576,16 @@ impl GoogleDriveRouter {
}) })
.unwrap_or(Ok(10))?; .unwrap_or(Ok(10))?;
let mut query_string = format!("name contains '{}'", query);
if let Some(m) = mime_type {
query_string.push_str(&format!(" and mimeType = '{}'", m));
}
let result = self let result = self
.drive .drive
.files() .files()
.list() .list()
.corpora(corpus) .corpora(corpus)
.q(format!("name contains '{}'", query).as_str()) .q(query_string.as_str())
.order_by("viewedByMeTime desc") .order_by("viewedByMeTime desc")
.param("fields", "files(id, name, mimeType, modifiedTime, size)") .param("fields", "files(id, name, mimeType, modifiedTime, size)")
.page_size(page_size) .page_size(page_size)
@@ -1415,7 +1429,7 @@ impl GoogleDriveRouter {
.await .await
} }
async fn list_comments(&self, params: Value) -> Result<Vec<Content>, ToolError> { async fn get_comments(&self, params: Value) -> Result<Vec<Content>, ToolError> {
let file_id = let file_id =
params params
.get("fileId") .get("fileId")
@@ -1424,7 +1438,9 @@ impl GoogleDriveRouter {
"The fileId param is required".to_string(), "The fileId param is required".to_string(),
))?; ))?;
// extract pageSize, and convert it to an i32, default to 10 let comment_id = params.get("commentId").and_then(|q| q.as_str());
// extract pageSize, and convert it to an i32, default to 20
let page_size: i32 = params let page_size: i32 = params
.get("pageSize") .get("pageSize")
.map(|s| { .map(|s| {
@@ -1432,60 +1448,95 @@ impl GoogleDriveRouter {
.and_then(|n| i32::try_from(n).ok()) .and_then(|n| i32::try_from(n).ok())
.ok_or_else(|| ToolError::InvalidParameters(format!("Invalid pageSize: {}", s))) .ok_or_else(|| ToolError::InvalidParameters(format!("Invalid pageSize: {}", s)))
.and_then(|n| { .and_then(|n| {
if (0..=100).contains(&n) { if (1..=100).contains(&n) {
Ok(n) Ok(n)
} else { } else {
Err(ToolError::InvalidParameters(format!( Err(ToolError::InvalidParameters(format!(
"pageSize must be between 0 and 100, got {}", "pageSize must be between 1 and 100, got {}",
n n
))) )))
} }
}) })
}) })
.unwrap_or(Ok(10))?; .unwrap_or(Ok(20))?;
let result = self if let Some(comment) = comment_id {
.drive // Use the get comment method to read a single comment
.comments() let result = self
.list(file_id) .drive
.page_size(page_size) .comments()
.param( .get(file_id, comment)
"fields", .param("fields", "*")
"comments(author, content, createdTime, modifiedTime, id, anchor, resolved)", .clear_scopes()
) .add_scope(GOOGLE_DRIVE_SCOPES)
.clear_scopes() .doit()
.add_scope(GOOGLE_DRIVE_SCOPES) .await;
.doit()
.await;
match result { match result {
Err(e) => Err(ToolError::ExecutionError(format!( Err(e) => Err(ToolError::ExecutionError(format!(
"Failed to execute google drive comment list, {}.", "Failed to execute google drive comment read, {}.",
e e
))), ))),
Ok(r) => { Ok(r) => {
let content = let content = format!(
r.1.comments "Author:{:?} Quoted File Content: {:?} Content: {} Replies: {:?} (created time: {}) (modified time: {})(anchor: {}) (resolved: {}) (id: {})",
.map(|comments| { r.1.author.unwrap_or_default(),
comments.into_iter().map(|c| { r.1.quoted_file_content.unwrap_or_default(),
format!( r.1.content.unwrap_or_default(),
"Author:{:?} Content: {} (created time: {}) (modified time: {})(anchor: {}) (resolved: {}) (id: {})", r.1.replies.unwrap_or_default(),
c.author.unwrap_or_default(), r.1.created_time.unwrap_or_default(),
c.content.unwrap_or_default(), r.1.modified_time.unwrap_or_default(),
c.created_time.unwrap_or_default(), r.1.anchor.unwrap_or_default(),
c.modified_time.unwrap_or_default(), r.1.resolved.unwrap_or_default(),
c.anchor.unwrap_or_default(), r.1.id.unwrap_or_default()
c.resolved.unwrap_or_default(), );
c.id.unwrap_or_default()
) Ok(vec![Content::text(content.to_string())])
}
}
} else {
let result = self
.drive
.comments()
.list(file_id)
.page_size(page_size)
.param(
"fields",
"comments(author, content, createdTime, modifiedTime, id, resolved)",
)
.clear_scopes()
.add_scope(GOOGLE_DRIVE_SCOPES)
.doit()
.await;
match result {
Err(e) => Err(ToolError::ExecutionError(format!(
"Failed to execute google drive comment list, {}.",
e
))),
Ok(r) => {
let content =
r.1.comments
.map(|comments| {
comments.into_iter().map(|c| {
format!(
"Author:{:?} Content: {} (created time: {}) (modified time: {}) (resolved: {}) (id: {})",
c.author.unwrap_or_default(),
c.content.unwrap_or_default(),
c.created_time.unwrap_or_default(),
c.modified_time.unwrap_or_default(),
c.resolved.unwrap_or_default(),
c.id.unwrap_or_default()
)
})
}) })
}) .into_iter()
.into_iter() .flatten()
.flatten() .collect::<Vec<_>>()
.collect::<Vec<_>>() .join("\n");
.join("\n");
Ok(vec![Content::text(content.to_string())]) Ok(vec![Content::text(content.to_string())])
}
} }
} }
} }
@@ -1527,7 +1578,7 @@ impl Router for GoogleDriveRouter {
"update" => this.update(arguments).await, "update" => this.update(arguments).await,
"update_file" => this.update_file(arguments).await, "update_file" => this.update_file(arguments).await,
"sheets_tool" => this.sheets_tool(arguments).await, "sheets_tool" => this.sheets_tool(arguments).await,
"list_comments" => this.list_comments(arguments).await, "get_comments" => this.get_comments(arguments).await,
_ => Err(ToolError::NotFound(format!("Tool {} not found", tool_name))), _ => Err(ToolError::NotFound(format!("Tool {} not found", tool_name))),
} }
}) })