관리-도구
편집 파일: base.php
<?php class Meow_MWAI_Query_Base implements JsonSerializable { // Environment public ?string $session = null; public ?string $chatId = null; public string $scope = ''; private $core = null; // Core Content public ?string $instructions = null; public array $messages = []; public ?string $context = null; public string $message = ''; // Parameters public int $maxMessages = 15; public int $maxResults = 1; public ?string $model = null; public string $feature = 'completion'; // Functions public array $functions = []; public ?string $functionCall = null; // MCP Servers public array $mcpServers = []; // Tools (for Responses API) public array $tools = []; // History strategy for Responses API public ?string $historyStrategy = null; public ?string $previousResponseId = null; // Overrides for env public array $envSettings = []; public string $envId = ''; public ?string $apiKey = null; // Seem to be only used by the Assistants, to get the current thread/discussion. // Maybe we should try to move this to the assistant class, or use it as ExtraParams. public ?string $botId = null; // Identifier for ad-hoc/custom chatbots (distinct from registered botId) public ?string $customId = null; // Embeddings configuration public ?string $embeddingsEnvId = null; // Extra Parameters (used by specific services, or for statistics, etc) public array $extraParams = []; /** * Internal state tracking for function call recursion. * Stores the configured max depth to prevent re-applying the filter on recursive calls. * Set once by engines/core.php during the first run() call. * @internal */ public $_maxDepthConfigured = null; // Options // Engine will either upload or share an URL to the image, for Vision, for example. // Having this here allows other services to override it if needed (Ollama needs it false). public ?string $image_remote_upload = null; #region Constructors, Serialization public function __construct( $message = '' ) { global $mwai_core; if ( is_string( $message ) ) { $this->set_message( $message ); } $this->session = $mwai_core->get_session_id(); $this->core = $mwai_core; $this->image_remote_upload = $this->core->get_option( 'image_remote_upload' ); } #[\ReturnTypeWillChange] public function jsonSerialize(): array { $json = [ 'message' => $this->message, 'instructions' => $this->instructions, 'ai' => [ 'model' => $this->model, 'feature' => $this->feature, ], 'system' => [ 'class' => get_class( $this ), 'envId' => $this->envId, 'scope' => $this->scope, 'session' => $this->session, 'customId' => $this->customId, 'maxMessages' => $this->maxMessages, ] ]; if ( !empty( $this->context ) ) { $json['context']['content'] = $this->context; } return $json; } #endregion #region Functions public function add_function( Meow_MWAI_Query_Function $function ): void { $this->functions[] = $function; $this->functionCall = 'auto'; } public function set_functions( array $functions ): void { $this->functions = $functions; $this->functionCall = 'auto'; } public function set_tools( array $tools ): void { $this->tools = $tools; } public function set_mcp_servers( array $mcpServers ): void { $this->mcpServers = $mcpServers; } #endregion #region Helpers public function replace( $search, $replace ) { $this->message = str_replace( $search, $replace, $this->message ); } #endregion public function get_message(): string { return $this->message; } public function get_in_tokens(): int { $text = ''; foreach ( $this->messages as $message ) { $text .= isset( $message['content']['text'] ) ? $message['content']['text'] : ''; $text .= isset( $message['content'] ) && is_string( $message['content'] ) ? $message['content'] : ''; } $text .= $this->message; $text .= $this->context ?? ''; return Meow_MWAI_Core::estimate_tokens( $text ); } /** * The environment, like "chatbot", "imagesbot", "chatbot-007", "textwriter", etc... * Used for statistics, mainly. * @param string $env The environment. */ public function set_scope( string $scope ): void { $this->scope = $scope; } /** * The environment ID for AI services. * Used for statistics, mainly. * @param string $envId The environment ID. */ public function set_env_id( string $envId ): void { $this->envId = $envId; } /** * ID of the model to use. * @param string $model ID of the model to use. */ public function set_model( string $model ) { $this->model = $model; } public function get_model() { return $this->model; } /** * The chat ID to use. * @param string $chatId The chat ID. */ public function set_chat_id( string $chatId ) { $this->chatId = $chatId; } public function get_chat_id() { return $this->chatId; } /** * The instructions are used to define the personality of the AI, and to give it some context. * @param string $instructions The instructions. */ public function set_instructions( string $instructions ): void { global $mwai_core; // Decode HTML entities in case the instructions were sanitized at the UI level // and ended up encoded when reaching the server. $instructions = html_entity_decode( $instructions ); // Apply filters first, so developers can add their own placeholders $filtered = apply_filters( 'mwai_ai_context', $instructions, $this ); if ( $filtered !== $instructions ) { Meow_MWAI_Logging::deprecated( '"mwai_ai_context" filter is deprecated. Please use "mwai_ai_instructions" instead.' ); } $filtered = apply_filters( 'mwai_ai_instructions', $filtered, $this ); // Apply placeholders (e.g., {DATE_TIME}, {DISPLAY_NAME}, etc.) after filters, // so custom placeholders added by developers are also processed. if ( $mwai_core ) { $filtered = $mwai_core->do_placeholders( $filtered ); } $this->instructions = $filtered; } /** * Given a message, the model will return one or more predicted completions. * It can also return the probabilities of alternative tokens at each position. * @param string $message The message to generate completions. */ public function set_message( string $message ) { $this->message = $message; } /** * Similar to the prompt, but use an array of messages instead. * @param string $messages The messages to generate completions. */ public function set_messages( array $messages ) { $messages = array_map( function ( $message ) { if ( is_array( $message ) ) { return [ 'role' => $message['role'], 'content' => $message['content'] ]; } else if ( is_object( $message ) ) { return [ 'role' => $message->role, 'content' => $message->content ]; } else { throw new InvalidArgumentException( 'Unsupported message type.' ); } }, $messages ); $this->messages = $messages; } /** * The context can be used to add additional information that is likely to be relevant to the model. * @param string $context The context. */ public function set_context( string $context ): void { $this->context = $context; } /** * The API key to use. * @param string $apiKey The API key. */ public function set_api_key( string $apiKey ) { $this->apiKey = $apiKey; } /** * The session ID to use. * @param string $session The session ID. */ public function set_session( string $session ) { $this->session = $session; } /** * The bot ID to use. * @param string $botId The bot ID. */ public function set_bot_id( string $botId ) { $this->botId = $botId; } /** * The custom ID to use for ad-hoc chatbots (shortcode/overrides). * @param string $customId The custom chatbot ID. */ public function set_custom_id( string $customId ) { $this->customId = $customId; } /** * The embeddings environment ID to use. * @param string $embeddingsEnvId The embeddings environment ID. */ public function set_embeddings_env_id( string $embeddingsEnvId ) { $this->embeddingsEnvId = $embeddingsEnvId; } /** * How many completions to generate for each prompt. * Because this parameter generates many completions, it can quickly consume your token quota. * Use carefully and ensure that you have reasonable settings for max_tokens and stop. * @param float $maxResults Number of completions. */ public function set_max_results( int $maxResults ) { $this->maxResults = $maxResults; } /** * Set the history strategy for Responses API. * @param string $historyStrategy The history strategy ('internal', 'response_id', or null). */ public function set_history_strategy( ?string $historyStrategy ) { $this->historyStrategy = $historyStrategy; } /** * Set the previous response ID for Responses API. * @param string $previousResponseId The previous response ID. */ public function set_previous_response_id( ?string $previousResponseId ) { $this->previousResponseId = $previousResponseId; } /** * This is run at the end of the process, to do some final checks. */ public function final_checks() { if ( !empty( $this->maxMessages ) ) { $context = array_shift( $this->messages ); if ( !empty( $this->messages ) ) { $this->messages = array_slice( $this->messages, -$this->maxMessages ); } else { $this->messages = []; } if ( !empty( $context ) ) { array_unshift( $this->messages, $context ); } } } public function set_max_messages( int $maxMessages ): void { if ( !empty( $maxMessages ) ) { $this->maxMessages = intval( $maxMessages ); } } protected function convert_keys( $params ) { $newParams = []; foreach ( $params as $key => $value ) { // Skip non-string keys (numeric indices, booleans, etc.) if ( !is_string( $key ) ) { continue; } $newKey = ''; $capitalizeNextChar = false; for ( $i = 0; $i < strlen( $key ); $i++ ) { if ( $key[$i] == '_' ) { $capitalizeNextChar = true; } else { $newKey .= $capitalizeNextChar ? strtoupper( $key[$i] ) : $key[$i]; $capitalizeNextChar = false; } } $newParams[$newKey] = $value; } return $newParams; } public function toJson() { return json_encode( $this ); } #region Extra Params public function setExtraParam( string $key, $value ): void { $this->extraParams[$key] = $value; } public function getExtraParam( string $key ) { // Only if it exists if ( !isset( $this->extraParams[$key] ) ) { return null; } $value = $this->extraParams[$key]; return $value; } #endregion Extra Params // Based on the params of the query, update the attributes public function inject_params( array $params ): void { // Those are for the keys passed directly by the shortcode. $params = $this->convert_keys( $params ); if ( !empty( $params['instructions'] ) ) { $this->set_instructions( $params['instructions'] ); } // Do not allow external params to clobber an already-set message // The message is typically set via constructor (e.g., Chatbot newMessage). // Some UIs may accidentally send a top-level 'message' param (e.g., from // unrelated settings like verbosity defaults), which would override the // real user input here. Only set it if it's not already set. if ( !empty( $params['message'] ) && $this->message === '' ) { $this->set_message( $params['message'] ); } if ( !empty( $params['messages'] ) ) { $this->set_messages( $params['messages'] ); } if ( !empty( $params['maxMessages'] ) && intval( $params['maxMessages'] ) > 0 ) { $this->set_max_messages( intval( $params['maxMessages'] ) ); } if ( !empty( $params['maxResults'] ) ) { $this->set_max_results( $params['maxResults'] ); } if ( !empty( $params['scope'] ) ) { $this->set_scope( $params['scope'] ); } if ( !empty( $params['session'] ) ) { $this->set_session( $params['session'] ); } if ( !empty( $params['apiKey'] ) ) { $this->set_api_key( $params['apiKey'] ); } if ( !empty( $params['botId'] ) ) { $this->set_bot_id( $params['botId'] ); } if ( !empty( $params['customId'] ) ) { $this->set_custom_id( $params['customId'] ); } if ( !empty( $params['envId'] ) ) { $this->set_env_id( $params['envId'] ); } if ( !empty( $params['model'] ) ) { $this->set_model( $params['model'] ); } if ( !empty( $params['chatId'] ) ) { $this->set_chat_id( $params['chatId'] ); } if ( !empty( $params['tools'] ) && is_array( $params['tools'] ) ) { $this->set_tools( $params['tools'] ); } if ( isset( $params['historyStrategy'] ) ) { $this->set_history_strategy( $params['historyStrategy'] ); } if ( !empty( $params['previousResponseId'] ) ) { $this->set_previous_response_id( $params['previousResponseId'] ); } if ( !empty( $params['embeddingsEnvId'] ) ) { $this->set_embeddings_env_id( $params['embeddingsEnvId'] ); } if ( !empty( $params['mcpServers'] ) ) { // Handle both JSON string and array formats $mcpServers = $params['mcpServers']; if ( is_string( $mcpServers ) ) { $mcpServers = json_decode( $mcpServers, true ); } if ( is_array( $mcpServers ) ) { $this->set_mcp_servers( $mcpServers ); } } } }