Files
openhuman/src/lib/mcp/telegram/toolActionParser.ts
T
Steven EnamakelandGitHub 520bfdb74c Fix/telegram login (#4)
* Add UserProvider to App component and enhance user data fetching logic

- Integrated UserProvider into the App component to manage user state.
- Updated UserProvider to fetch current user data on token availability and handle token expiration by clearing the token on fetch failure.
- Improved user data fetching logic for better error handling and user experience.

* Enhance Telegram connection handling and error management

- Added logic to handle Telegram account mismatch, providing user feedback and resetting connection state.
- Improved user verification during authentication to ensure the logged-in account matches the Telegram account.
- Refactored connection status checks and error handling for better user experience.
- Introduced a method to clear session and disconnect when account mismatch occurs.
- Updated polling mechanism for authentication status to ensure timely updates.

This update improves the robustness of the Telegram connection process and enhances user feedback during authentication failures.

* ran prettier

* Refactor socket and auth state management for user-specific handling

- Updated socket state management to support multiple users by introducing user-specific selectors and actions.
- Refactored connection status handling in the socket service to dispatch user-specific status updates.
- Enhanced onboarding state management to track completion per user, allowing for more granular control.
- Introduced new selectors for socket and auth states to improve readability and maintainability.
- Updated relevant components to utilize the new user-specific state management.

This update improves the application's ability to handle multiple users and enhances the overall user experience during onboarding and socket connections.

* Enhance MTProto client session management and introduce user-specific session handling

- Updated the MTProtoService to manage sessions per user by storing session data under a user-specific key.
- Modified the initialize method to accept a userId parameter, allowing for user-specific session initialization and management.
- Improved session loading and saving logic to ensure proper handling of user sessions.
- Added a utility function to generate session keys based on userId for better maintainability.

This update enhances the application's ability to handle multiple user sessions effectively.

* Refactor Telegram state management for user-specific handling

- Introduced user-specific state management in the Telegram store, allowing for better handling of multiple users.
- Updated selectors to retrieve state based on the current user, improving data encapsulation and reducing global state dependencies.
- Enhanced reducers and thunks to ensure actions are dispatched with user context, maintaining user-specific data integrity.
- Modified persistence configuration to store Telegram state scoped by user, ensuring isolated state management.

This update significantly improves the application's ability to manage multiple user sessions effectively and enhances overall user experience.

* Enhance MTProtoService connection handling with user-specific initialization

- Updated the checkConnection method to accept an optional userId parameter, allowing for user-specific connection initialization.
- Modified the connection logic to ensure proper initialization only occurs when a userId is provided, improving session management.
- Refactored related thunks to use a consistent naming convention for userId parameters, enhancing code clarity.

This update improves the handling of user sessions in the MTProtoService, aligning with recent enhancements in user-specific state management.

* Refactor Telegram connection handling for user-specific management

- Updated the TelegramConnectionModal to utilize user-specific identifiers for connection status and authentication processes, enhancing session management.
- Refactored related components and selectors to ensure userId is consistently passed and utilized, improving clarity and maintainability.
- Enhanced the ConnectionsPanel and ConnectStep to check for saved sessions based on userId, allowing for better handling of multiple user connections.

This update significantly improves the application's ability to manage user-specific Telegram connections and enhances the overall user experience.

* Refactor Telegram connection logic to simplify session management

- Removed unnecessary userId checks and localStorage interactions from ConnectionsPanel and ConnectStep components, streamlining the connection status determination.
- Updated MTProtoService to manage session data through Redux instead of localStorage, enhancing consistency and maintainability.
- Improved session loading and saving logic to focus solely on Redux state, ensuring better integration with user-specific session handling.

This update enhances the clarity and efficiency of the Telegram connection management process, aligning with recent improvements in user-specific state management.

* Update CLAUDE.md to clarify localStorage usage and emphasize Redux for state management

- Revised documentation to discourage the use of localStorage and sessionStorage for app state, advocating for Redux and Redux Persist instead.
- Added guidelines for removing existing localStorage usage and migrating relevant data to Redux.
- Updated service layer documentation to reflect changes in session management, specifying that session data is now stored in Redux rather than localStorage.
- Enhanced clarity on deep link handling and the prevention of infinite reload loops.

This update aligns with recent improvements in user-specific state management and reinforces best practices for state handling.

* Enhance onboarding process with error handling and API integration

- Updated the Onboarding component to include an API call for marking onboarding as complete, with error handling to provide user feedback.
- Refactored the GetStartedStep component to support asynchronous completion handling, including loading state and error messages.
- Introduced a new onboardingComplete method in the userApi service to facilitate the onboarding completion process.

This update improves the user experience during onboarding by ensuring proper error management and feedback.

* Enhance TelegramConnectionModal with socket connection management and improved initialization flow

- Integrated socket connection handling in the TelegramConnectionModal to ensure the socket is connected when the modal opens, enhancing real-time features.
- Refactored the initialization logic to streamline the connection process, including user verification and error handling.
- Introduced a reference to track the QR code flow state, preventing multiple initiations and improving user experience during authentication.

This update improves the reliability of the Telegram connection process and enhances user feedback during the onboarding experience.

* Refactor Telegram connection checks for improved logic consistency

- Updated the ConnectionsPanel and ConnectStep components to refine the logic for determining if a Telegram connection is established, ensuring that both session string and authentication status are required for a valid connection.
- Simplified className definitions in the UI components for better readability and maintainability.

This update enhances the clarity of connection status checks and improves the overall user experience during the onboarding process.

* Refactor Telegram authentication flow and improve error handling

- Simplified the TelegramLoginButton component by removing complex authentication logic and replacing it with a direct link to the Telegram bot for login.
- Enhanced the Login page to consume a login token from the URL, providing better error handling and user feedback during the authentication process.
- Introduced a new API service for consuming login tokens, ensuring secure retrieval of JWT tokens from the backend.

This update streamlines the authentication experience and improves error management, enhancing overall user experience during login.
2026-01-29 07:38:34 +05:30

352 lines
14 KiB
TypeScript

/**
* Tool Action Parser - Converts tool inputs to human-readable descriptions
*/
type ToolArguments = Record<string, unknown>;
function formatId(id: string | number | undefined, prefix = ""): string {
if (!id) return "";
const str = String(id);
return prefix ? `${prefix} ${str}` : str;
}
function truncateText(text: string, maxLength = 50): string {
if (text.length <= maxLength) return text;
return `${text.substring(0, maxLength)}...`;
}
export function toHumanReadableAction(
toolName: string,
args: ToolArguments,
): string {
const parser = toolParsers[toolName];
if (parser) return parser(args);
return `Executing ${toolName} with provided parameters`;
}
const toolParsers: Record<string, (args: ToolArguments) => string> = {
send_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const message = truncateText((args.message as string) || "", 100);
return `Send message to ${chatId}: "${message}"`;
},
reply_to_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const text = truncateText((args.text as string) || "", 100);
return `Reply to message ${messageId} in ${chatId}: "${text}"`;
},
edit_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const newText = truncateText((args.new_text as string) || "", 100);
return `Edit message ${messageId} in ${chatId} to: "${newText}"`;
},
delete_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
return `Delete message ${messageId} from ${chatId}`;
},
forward_message: (args) => {
const fromChat = formatId(args.from_chat_id as string | number, "chat");
const toChat = formatId(args.to_chat_id as string | number, "chat");
const messageId = args.message_id;
return `Forward message ${messageId} from ${fromChat} to ${toChat}`;
},
pin_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
return `Pin message ${messageId} in ${chatId}`;
},
unpin_message: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
return `Unpin message ${messageId} in ${chatId}`;
},
mark_as_read: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Mark messages as read in ${chatId}`;
},
send_reaction: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const reaction = (args.reaction as string) || "👍";
return `Add reaction ${reaction} to message ${messageId} in ${chatId}`;
},
remove_reaction: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const reaction = (args.reaction as string) || "";
return `Remove reaction ${reaction} from message ${messageId} in ${chatId}`;
},
save_draft: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const text = truncateText((args.text as string) || "", 50);
return `Save draft in ${chatId}: "${text}"`;
},
clear_draft: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Clear draft in ${chatId}`;
},
list_chats: (args) => {
const chatType = (args.chat_type as string) || "all";
const limit = (args.limit as number) || 20;
return `List ${limit} ${chatType} chats`;
},
get_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get information for ${chatId}`;
},
create_group: (args) => {
const title = (args.title as string) || "Untitled Group";
const userCount = Array.isArray(args.user_ids) ? args.user_ids.length : 0;
return `Create group "${title}" with ${userCount} member${userCount !== 1 ? "s" : ""}`;
},
create_channel: (args) => {
const title = (args.title as string) || "Untitled Channel";
const description = args.description
? `: ${truncateText((args.description as string) || "", 50)}`
: "";
return `Create channel "${title}"${description}`;
},
edit_chat_title: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const newTitle = (args.new_title as string) || "";
return `Change title of ${chatId} to "${newTitle}"`;
},
delete_chat_photo: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Remove photo from ${chatId}`;
},
edit_chat_photo: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Update photo for ${chatId}`;
},
leave_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Leave ${chatId}`;
},
mute_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const muteFor = args.mute_for ? ` for ${args.mute_for} seconds` : "";
return `Mute ${chatId}${muteFor}`;
},
unmute_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Unmute ${chatId}`;
},
archive_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Archive ${chatId}`;
},
unarchive_chat: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Unarchive ${chatId}`;
},
invite_to_group: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const userCount = Array.isArray(args.user_ids) ? args.user_ids.length : 0;
return `Invite ${userCount} user${userCount !== 1 ? "s" : ""} to ${chatId}`;
},
ban_user: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const userId = formatId(args.user_id as string | number, "user");
return `Ban ${userId} from ${chatId}`;
},
unban_user: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const userId = formatId(args.user_id as string | number, "user");
return `Unban ${userId} from ${chatId}`;
},
promote_admin: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const userId = formatId(args.user_id as string | number, "user");
return `Promote ${userId} to admin in ${chatId}`;
},
demote_admin: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const userId = formatId(args.user_id as string | number, "user");
return `Demote ${userId} from admin in ${chatId}`;
},
block_user: (args) => {
const userId = formatId(args.user_id as string | number, "user");
return `Block ${userId}`;
},
unblock_user: (args) => {
const userId = formatId(args.user_id as string | number, "user");
return `Unblock ${userId}`;
},
add_contact: (args) => {
const firstName = (args.first_name as string) || "";
const lastName = (args.last_name as string) || "";
const phone = (args.phone_number as string) || "";
const name = [firstName, lastName].filter(Boolean).join(" ") || phone;
return `Add contact: ${name}`;
},
delete_contact: (args) => {
const userId = formatId(args.user_id as string | number, "user");
return `Delete contact ${userId}`;
},
list_contacts: (args) => {
const limit = (args.limit as number) || 20;
return `List ${limit} contacts`;
},
search_contacts: (args) => {
const query = truncateText((args.query as string) || "", 30);
return `Search contacts for "${query}"`;
},
search_messages: (args) => {
const chatId = args.chat_id
? formatId(args.chat_id as string | number, "chat")
: "all chats";
const query = truncateText((args.query as string) || "", 30);
const limit = (args.limit as number) || 20;
return `Search for "${query}" in ${chatId} (limit: ${limit})`;
},
search_public_chats: (args) => {
const query = truncateText((args.query as string) || "", 30);
return `Search public chats for "${query}"`;
},
resolve_username: (args) => {
const username = (args.username as string) || "";
return `Resolve username @${username.replace("@", "")}`;
},
get_messages: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const limit = (args.limit as number) || 20;
return `Get ${limit} messages from ${chatId}`;
},
list_messages: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const limit = (args.limit as number) || 20;
return `List ${limit} messages from ${chatId}`;
},
get_history: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const limit = (args.limit as number) || 20;
return `Get message history from ${chatId} (${limit} messages)`;
},
get_pinned_messages: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get pinned messages from ${chatId}`;
},
get_message_context: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const limit = (args.limit as number) || 5;
return `Get context around message ${messageId} in ${chatId}${limit} messages)`;
},
list_topics: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `List topics in ${chatId}`;
},
get_participants: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const limit = (args.limit as number) || 100;
return `Get ${limit} participants from ${chatId}`;
},
get_admins: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get administrators of ${chatId}`;
},
get_banned_users: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get banned users from ${chatId}`;
},
get_blocked_users: () => "Get list of blocked users",
get_invite_link: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get invite link for ${chatId}`;
},
export_chat_invite: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Create invite link for ${chatId}`;
},
import_chat_invite: (args) => {
const inviteHash = args.invite_hash
? truncateText((args.invite_hash as string) || "", 20)
: "";
return `Join chat via invite link: ${inviteHash}`;
},
join_chat_by_link: (args) => {
const inviteLink = args.invite_link
? truncateText((args.invite_link as string) || "", 30)
: "";
return `Join chat via link: ${inviteLink}`;
},
subscribe_public_channel: (args) => {
const username = (args.username as string) || "";
return `Subscribe to public channel @${username.replace("@", "")}`;
},
update_profile: (args) => {
const updates: string[] = [];
if (args.first_name)
updates.push(`first name: "${args.first_name as string}"`);
if (args.last_name)
updates.push(`last name: "${args.last_name as string}"`);
if (args.bio)
updates.push(`bio: "${truncateText((args.bio as string) || "", 30)}"`);
return `Update profile (${updates.join(", ")})`;
},
set_profile_photo: () => "Set profile photo",
delete_profile_photo: () => "Delete profile photo",
get_user_photos: (args) => {
const userId = formatId(args.user_id as string | number, "user");
const limit = (args.limit as number) || 20;
return `Get ${limit} photos from ${userId}`;
},
get_user_status: (args) => {
const userId = formatId(args.user_id as string | number, "user");
return `Get status of ${userId}`;
},
get_me: () => "Get current user information",
list_inline_buttons: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
return `Get inline buttons from message ${messageId} in ${chatId}`;
},
press_inline_button: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
const buttonText = args.button_text
? ` "${truncateText((args.button_text as string) || "", 30)}"`
: "";
return `Press inline button${buttonText} on message ${messageId} in ${chatId}`;
},
create_poll: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const question = truncateText((args.question as string) || "", 50);
const optionCount = Array.isArray(args.options) ? args.options.length : 0;
return `Create poll in ${chatId}: "${question}" with ${optionCount} options`;
},
get_bot_info: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
return `Get bot information from ${chatId}`;
},
set_bot_commands: (args) => {
const chatId = args.chat_id
? formatId(args.chat_id as string | number, "chat")
: "all chats";
const commandCount = Array.isArray(args.commands)
? args.commands.length
: 0;
return `Set ${commandCount} bot commands for ${chatId}`;
},
get_privacy_settings: () => "Get privacy settings",
set_privacy_settings: (args) => {
const setting = (args.setting as string) || "unknown";
const value = (args.value as string) || "";
return `Set privacy setting "${setting}" to ${value}`;
},
get_media_info: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const messageId = args.message_id;
return `Get media information from message ${messageId} in ${chatId}`;
},
get_recent_actions: (args) => {
const chatId = formatId(args.chat_id as string | number, "chat");
const limit = (args.limit as number) || 20;
return `Get ${limit} recent admin actions from ${chatId}`;
},
};