diff --git a/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.py b/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.py new file mode 100644 index 00000000000000..7152f7816a8b32 --- /dev/null +++ b/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.py @@ -0,0 +1,101 @@ +import uuid +from datetime import UTC, datetime +from typing import Any, Union + +from azure.core.exceptions import ResourceExistsError +from azure.storage.blob import BlobServiceClient, ContentSettings + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.errors import ToolProviderCredentialValidationError +from core.tools.tool.builtin_tool import BuiltinTool + + +class WriteLogFileTool(BuiltinTool): + """ + Write log file to Azure Blob Storage + """ + + def _invoke( + self, user_id: str, tool_parameters: dict[str, Any] + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + # Ensure runtime and credentials + if not self.runtime or not self.runtime.credentials: + raise ToolProviderCredentialValidationError("Tool runtime or credentials are missing") + + # Get account name + account_name = self.runtime.credentials.get("azure_blob_storage_account_name") + if not account_name: + raise ValueError("Azure Blob Storage connection string is required") + + # Get API key + api_key = self.runtime.credentials.get("azure_blob_storage_api_key") + if not api_key: + raise ValueError("Azure Blob Storage API Key is required") + + # get container name + container_name = tool_parameters.get("container_name") + if not container_name: + raise ValueError("Container name is required") + + # get log string + log_string = tool_parameters.get("log_string") + if not log_string: + raise ValueError("Log file is required") + + # get resouce name + resource_name = tool_parameters.get("resource_name", "default") + + # get file suffix + file_suffix = tool_parameters.get("file_suffix") + file_suffix_str = f"-{file_suffix}" if file_suffix else "" + + # get current time + current_time = datetime.now(UTC) + blob = ( + f"{resource_name}/" + f"{current_time.strftime('%Y/%m/%d/%H-%M-%S.%f')}-{uuid.uuid4().hex}" + f"{file_suffix_str}.log" + ) + + # get stop_on_error flag + stop_on_error = tool_parameters.get("stop_on_error", True) + + # create a blob client using the connection string + blob_service_client = BlobServiceClient( + account_url=f"https://{account_name}.blob.core.windows.net", credential=api_key + ) + + # create container + try: + blob_service_client.create_container(name=container_name) + except ResourceExistsError: + pass + except Exception as exc: + if stop_on_error: + raise ValueError("Failed to create container") from exc + else: + return [ + self.create_text_message("Failed to create container"), + self.create_json_message({"error": "Failed to create container"}), + ] + + # content setting + content_settings = ContentSettings(content_type="text/plain") + + # upload file to blob storage + blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob) + try: + blob_client.upload_blob(log_string, content_settings=content_settings) + except Exception as exc: + if stop_on_error: + raise ValueError("Failed to write log") from exc + else: + return [ + self.create_text_message("Failed to write log"), + self.create_json_message({"error": "Failed to write log"}), + ] + + return [ + self.create_text_message(f'Log file "{blob}" has been written to container "{container_name}"'), + self.create_json_message({"blob": blob, "container": container_name}), + ] diff --git a/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.yaml b/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.yaml new file mode 100644 index 00000000000000..6b0ca84145e9ef --- /dev/null +++ b/api/core/tools/provider/builtin/azure_blob_storage/tools/write_log_file.yaml @@ -0,0 +1,69 @@ +identity: + name: write_log_file + author: Hiroshi Fujita + label: + en_US: Write Log File + ja_JP: ログに書き出し +description: + human: + en_US: Write logs to Azure Blob Storage + ja_JP: ログをAzure Blob Storageに書き出し + llm: This tool write logs to Azure Blob Storage +parameters: + - name: log_string + type: string + required: true + label: + en_US: Log contents + ja_JP: ログの内容 + human_description: + en_US: SSelect what you want to write to the log. + ja_JP: ログに書き出す内容を選択します。 + llm_description: Select what you want to write to the log. + form: llm + - name: container_name + type: string + required: true + label: + en_US: Container name + ja_JP: コンテナ名 + human_description: + en_US: Name of the container to upload to + ja_JP: アップロード先のコンテナの名称 + llm_description: Name of the container to upload to + form: llm + - name: resource_name + type: string + required: true + label: + en_US: Resource Name + ja_JP: リソース名 + human_description: + en_US: The resource name is an identifier to distinguish the log category. A virtual folder with this name will be created just under the container root. + ja_JP: リソース名は、ログのカテゴリを区別するための識別名です。コンテナのルートのすぐ下に、この名前の仮想フォルダで作成されます。 + llm_description: The resource name is an identifier to distinguish the log category. A virtual folder with this name will be created just under the container root. + form: llm + default: default + - name: file_suffix + type: string + required: false + label: + en_US: File Suffix + ja_JP: ファイルサフィックス + human_description: + en_US: Blob names are classified into virtual folders by date and time to make them chronologically sortable, and consist of a timestamp and random characters to separate duplicates. You can add any characters to the end of this blob name. The extension .log is automatically added. + ja_JP: Blobの名称は時間軸でソート可能にするために、日時の仮想フォルダに分類され、タイムスタンプと重複を裂けるためのランダムな文字で構成されます。このblob名称の末尾には自由な文字を付与できます。拡張子は自動で.logが付与されます。 + llm_description: Blob names are classified into virtual folders by date and time to make them chronologically sortable, and consist of a timestamp and random characters to separate duplicates. You can add any characters to the end of this blob name. The extension .log is automatically added. + form: llm + - name: stop_on_error + type: boolean + required: true + label: + en_US: Stop on Error + ja_JP: エラー時に停止する + human_description: + en_US: Set whether to stop the flow if the file upload fails. + ja_JP: ファイルのアップロードが失敗した場合に、フローを止めるかを設定します。 + llm_description: Set whether to stop the flow if the file upload fails. + form: form + default: true