From 613d1a3da1efdc55535394b236cc5f6a07b83488 Mon Sep 17 00:00:00 2001 From: Edward Alvarado Date: Sat, 16 Nov 2024 11:27:18 -0300 Subject: [PATCH] TS Function name handling --- .../llm_language_support/language_helpers.rs | 66 +++++++++++++------ .../tool_definitions/definition_generation.rs | 14 +++- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/shinkai-bin/shinkai-node/src/tools/llm_language_support/language_helpers.rs b/shinkai-bin/shinkai-node/src/tools/llm_language_support/language_helpers.rs index 6f322766e..8600af7a4 100644 --- a/shinkai-bin/shinkai-node/src/tools/llm_language_support/language_helpers.rs +++ b/shinkai-bin/shinkai-node/src/tools/llm_language_support/language_helpers.rs @@ -1,16 +1,23 @@ -/// Converts a string to camelCase format +/// Converts a string to camelCase format, ensuring the result is a valid function name pub fn to_camel_case(s: &str) -> String { let mut result = String::new(); let mut capitalize_next = false; - + // First character should be lowercase in camelCase let mut chars = s.chars(); if let Some(first_char) = chars.next() { - result.push(first_char.to_ascii_lowercase()); + // Ensure first character is a letter, prepend 'fn' if not + if !first_char.is_alphabetic() { + result.push_str("fn"); + capitalize_next = true; + } + if !capitalize_next { + result.push(first_char.to_ascii_lowercase()); + } } - + for c in chars { - if c == '_' || c == '-' || c == ' ' { // Added space handling + if !c.is_alphanumeric() { capitalize_next = true; } else if capitalize_next { result.push(c.to_ascii_uppercase()); @@ -19,20 +26,38 @@ pub fn to_camel_case(s: &str) -> String { result.push(c.to_ascii_lowercase()); } } - + + // Handle empty string case + if result.is_empty() { + result.push_str("fn"); + } + result } -/// Converts a string to snake_case format +/// Converts a string to snake_case format, ensuring the result is a valid function name pub fn to_snake_case(s: &str) -> String { let mut result = String::new(); let mut prev_is_upper = true; - - let s = s.replace(' ', "_").replace('-', "_"); - - for c in s.chars() { - if c.is_uppercase() { - if !prev_is_upper && !result.is_empty() { + + // Ensure the name starts with a letter or underscore + let mut chars = s.chars(); + if let Some(first_char) = chars.next() { + if !first_char.is_alphabetic() { + result.push_str("fn_"); + } + if !result.starts_with("fn_") { + result.push(first_char.to_ascii_lowercase()); + } + } + + for c in chars { + if !c.is_alphanumeric() { + if !result.ends_with('_') { + result.push('_'); + } + } else if c.is_uppercase() { + if !prev_is_upper && !result.is_empty() && !result.ends_with('_') { result.push('_'); } result.push(c.to_ascii_lowercase()); @@ -42,9 +67,12 @@ pub fn to_snake_case(s: &str) -> String { prev_is_upper = false; } } - - result - .replace("__", "_") - .trim_matches('_') - .to_string() -} \ No newline at end of file + + // Handle empty string case + if result.is_empty() { + result.push_str("fn"); + } + + // Clean up multiple underscores and trailing/leading underscores + result.replace("__", "_").trim_end_matches('_').to_string() +} diff --git a/shinkai-bin/shinkai-node/src/tools/tool_definitions/definition_generation.rs b/shinkai-bin/shinkai-node/src/tools/tool_definitions/definition_generation.rs index a08974a60..0d9bd474f 100644 --- a/shinkai-bin/shinkai-node/src/tools/tool_definitions/definition_generation.rs +++ b/shinkai-bin/shinkai-node/src/tools/tool_definitions/definition_generation.rs @@ -1,6 +1,7 @@ use shinkai_http_api::node_api_router::APIError; use shinkai_message_primitives::schemas::shinkai_tools::CodeLanguage; use shinkai_sqlite::SqliteManager; +use std::collections::HashSet; use std::sync::Arc; use crate::tools::llm_language_support::generate_typescript::generate_typescript_definition; @@ -38,6 +39,8 @@ pub async fn generate_tool_definitions( all_tools.extend(get_custom_tools()); let mut output = String::new(); + let mut generated_names = HashSet::new(); + match language { CodeLanguage::Typescript => { if !only_headers { @@ -46,12 +49,21 @@ pub async fn generate_tool_definitions( } CodeLanguage::Python => { output.push_str("import os\nimport requests\nfrom typing import TypedDict, Optional\n\n"); - // output.push_str(&generate_python_definition(name, &runner_def)); } } + for tool in all_tools { match language { CodeLanguage::Typescript => { + let function_name = crate::tools::llm_language_support::language_helpers::to_camel_case(&tool.name); + if generated_names.contains(&function_name) { + eprintln!( + "Warning: Duplicate function name '{}' found for tool '{}'. Skipping generation.", + function_name, tool.name + ); + continue; + } + generated_names.insert(function_name); output.push_str(&generate_typescript_definition(tool, only_headers)); } CodeLanguage::Python => {