__( 'AI Chatbot, Agents & MCP for Amazon Bedrock configuration', 'ai-chat-for-amazon-bedrock' ),
'test' => array( $this, 'site_health_configuration' ),
);
return $tests;
}
/**
* Site Health result for plugin configuration.
*
* @return array
*/
public function site_health_configuration() {
$checks = $this->run( false );
$failed = array();
$warnings = array();
foreach ( $checks as $check ) {
if ( 'fail' === $check['status'] ) {
$failed[] = $check;
} elseif ( 'warn' === $check['status'] ) {
$warnings[] = $check;
}
}
$result = array(
'label' => __( 'Amazon Bedrock chat is configured correctly', 'ai-chat-for-amazon-bedrock' ),
'status' => 'good',
'badge' => array(
'label' => __( 'AI Chat Bedrock', 'ai-chat-for-amazon-bedrock' ),
'color' => 'blue',
),
'description' => '
' . esc_html__( 'Credentials, region, model access, and chat security defaults were verified.', 'ai-chat-for-amazon-bedrock' ) . '
',
'actions' => '',
'test' => 'ai_chat_bedrock_configuration',
);
$problems = array_merge( $failed, $warnings );
if ( ! empty( $problems ) ) {
$result['status'] = empty( $failed ) ? 'recommended' : 'critical';
$result['label'] = empty( $failed )
? __( 'Amazon Bedrock chat has configuration recommendations', 'ai-chat-for-amazon-bedrock' )
: __( 'Amazon Bedrock chat is not fully configured', 'ai-chat-for-amazon-bedrock' );
$items = '';
foreach ( $problems as $problem ) {
$items .= '' . esc_html( $problem['label'] ) . ': ' . esc_html( $problem['message'] ) . '';
}
$result['description'] = '';
$result['actions'] = sprintf(
'%s
',
esc_url( admin_url( 'admin.php?page=ai-chat-for-amazon-bedrock-diagnostics' ) ),
esc_html__( 'Open Bedrock diagnostics', 'ai-chat-for-amazon-bedrock' )
);
}
return $result;
}
/**
* Run configuration checks.
*
* @param bool $include_live Whether to perform a live Bedrock invocation.
* @return array
*/
public function run( $include_live = false ) {
$options = get_option( 'ai_chat_bedrock_settings', array() );
$options = is_array( $options ) ? $options : array();
$checks = array();
// Asked for a fresh look, as after attaching an IAM role, nothing remembered stands in for it.
if ( $include_live && class_exists( 'AI_Chat_Bedrock_AWS_Credentials' ) ) {
AI_Chat_Bedrock_AWS_Credentials::flush_cache();
}
$checks[] = $this->check_php();
$checks[] = $this->check_credentials( $options );
$checks[] = $this->check_region( $options );
$checks[] = $this->check_model( $options );
$checks[] = $this->check_streaming( $options );
$checks[] = $this->check_encryption();
$checks[] = $this->check_public_access( $options );
$checks[] = $this->check_mcp();
if ( class_exists( 'AI_Chat_Bedrock_Ontology' ) ) {
$checks[] = $this->check_agents();
}
$checks[] = $this->check_schedules();
$checks[] = $this->check_guardrail( $options );
$checks[] = $this->check_knowledge_base( $options );
$checks[] = $this->check_vector_store( $options );
if ( $include_live ) {
$checks[] = $this->check_live_invocation( $options );
}
return $checks;
}
private function check_php() {
$ok = version_compare( PHP_VERSION, '7.4', '>=' );
return $this->result(
'php',
__( 'PHP version', 'ai-chat-for-amazon-bedrock' ),
$ok ? 'pass' : 'fail',
$ok
/* translators: %s: PHP version. */
? sprintf( __( 'PHP %s meets the plugin requirement.', 'ai-chat-for-amazon-bedrock' ), PHP_VERSION )
: __( 'PHP 7.4 or newer is required.', 'ai-chat-for-amazon-bedrock' )
);
}
private function check_credentials( $options ) {
$status = AI_Chat_Bedrock_AWS_Credentials::describe( $options );
if ( ! $status['configured'] ) {
return $this->result( 'credentials', __( 'AWS credentials', 'ai-chat-for-amazon-bedrock' ), 'fail', __( 'No usable AWS credentials were found. Paste an Amazon Bedrock API key, add access keys, or enable IAM role credentials.', 'ai-chat-for-amazon-bedrock' ) );
}
$state = in_array( $status['source'], array( 'options' ), true ) ? 'warn' : 'pass';
$message = $status['message'];
if ( 'options' === $status['source'] ) {
$message = AI_Chat_Bedrock_Translation::sentences( $message, __( 'Consider wp-config.php constants or an IAM role so keys are not stored in the database.', 'ai-chat-for-amazon-bedrock' ) );
}
if ( 0 === strpos( $status['source'], 'api_key_' ) ) {
if ( ! empty( $status['temporary'] ) ) {
$state = 'warn';
$message = AI_Chat_Bedrock_Translation::sentences( $message, __( 'This is a short-term key, which stops working within 12 hours. Use a long-term key or an IAM role.', 'ai-chat-for-amazon-bedrock' ) );
}
// Agents endpoints refuse API keys, so a feature that uses them needs signing credentials too.
$needs_signing = ! empty( $options['knowledge_base_id'] ) || ! empty( $options['prompt_id'] );
if ( $needs_signing && ! ( new AI_Chat_Bedrock_AWS() )->has_signing_credentials() ) {
$state = 'warn';
$message = AI_Chat_Bedrock_Translation::sentences( $message, __( 'A Knowledge Base or managed prompt is configured, and those only accept signed requests. Add access keys or an IAM role for them; chat keeps using the API key.', 'ai-chat-for-amazon-bedrock' ) );
}
}
return $this->result( 'credentials', __( 'AWS credentials', 'ai-chat-for-amazon-bedrock' ), $state, $message );
}
private function check_region( $options ) {
$region = isset( $options['aws_region'] ) ? sanitize_key( $options['aws_region'] ) : '';
$regions = AI_Chat_Bedrock_Models::regions();
if ( '' === $region || ! isset( $regions[ $region ] ) ) {
return $this->result( 'region', __( 'AWS region', 'ai-chat-for-amazon-bedrock' ), 'fail', __( 'Select a supported AWS region for Amazon Bedrock.', 'ai-chat-for-amazon-bedrock' ) );
}
return $this->result( 'region', __( 'AWS region', 'ai-chat-for-amazon-bedrock' ), 'pass', $regions[ $region ] . ' (' . $region . ')' );
}
private function check_model( $options ) {
$model = isset( $options['model_id'] ) ? (string) $options['model_id'] : '';
if ( ! AI_Chat_Bedrock_Models::is_valid_id( $model ) ) {
return $this->result( 'model', __( 'Model selection', 'ai-chat-for-amazon-bedrock' ), 'fail', __( 'Select a Bedrock model in the settings.', 'ai-chat-for-amazon-bedrock' ) );
}
$catalog = AI_Chat_Bedrock_Models::options();
if ( ! isset( $catalog[ $model ] ) ) {
return $this->result( 'model', __( 'Model selection', 'ai-chat-for-amazon-bedrock' ), 'warn', __( 'The selected model was not returned by the region catalog. Confirm the region offers it and whether an inference profile ID is required.', 'ai-chat-for-amazon-bedrock' ) );
}
return $this->result( 'model', __( 'Model selection', 'ai-chat-for-amazon-bedrock' ), 'pass', $model );
}
private function check_streaming( $options ) {
$requested = ! isset( $options['enable_streaming'] ) || 'off' !== $options['enable_streaming'];
$supported = AI_Chat_Bedrock_AWS::streaming_supported();
if ( ! $requested ) {
return $this->result( 'streaming', __( 'Streaming', 'ai-chat-for-amazon-bedrock' ), 'warn', __( 'Streaming is disabled, so answers appear only when generation finishes.', 'ai-chat-for-amazon-bedrock' ) );
}
if ( ! $supported ) {
return $this->result( 'streaming', __( 'Streaming', 'ai-chat-for-amazon-bedrock' ), 'warn', __( 'The PHP cURL extension is unavailable, so buffered responses are used instead of streaming.', 'ai-chat-for-amazon-bedrock' ) );
}
return $this->result( 'streaming', __( 'Streaming', 'ai-chat-for-amazon-bedrock' ), 'pass', __( 'Streaming responses are enabled with automatic fallback.', 'ai-chat-for-amazon-bedrock' ) );
}
private function check_encryption() {
$ok = function_exists( 'sodium_crypto_secretbox' );
return $this->result(
'encryption',
__( 'Credential encryption', 'ai-chat-for-amazon-bedrock' ),
$ok ? 'pass' : 'warn',
$ok
? __( 'Stored credentials are encrypted with authenticated encryption.', 'ai-chat-for-amazon-bedrock' )
: __( 'Sodium is unavailable, so credentials cannot be encrypted in the database. Use wp-config.php constants or an IAM role.', 'ai-chat-for-amazon-bedrock' )
);
}
private function check_public_access( $options ) {
if ( empty( $options['allow_public_chat'] ) ) {
return $this->result( 'guest_access', __( 'Guest access', 'ai-chat-for-amazon-bedrock' ), 'pass', __( 'Only signed-in users can start paid Bedrock requests.', 'ai-chat-for-amazon-bedrock' ) );
}
$limit = isset( $options['rate_limit_per_minute'] ) ? absint( $options['rate_limit_per_minute'] ) : 5;
// Report the limit guests actually get, which a per-role override can change.
$guest_limit = $limit;
if ( class_exists( 'AI_Chat_Bedrock_Rate_Limits' ) ) {
$overrides = AI_Chat_Bedrock_Rate_Limits::all();
if ( isset( $overrides[ AI_Chat_Bedrock_Rate_Limits::GUEST_KEY ] ) ) {
$guest_limit = (int) $overrides[ AI_Chat_Bedrock_Rate_Limits::GUEST_KEY ];
}
}
return $this->result(
'guest_access',
__( 'Guest access', 'ai-chat-for-amazon-bedrock' ),
'warn',
sprintf(
/* translators: %s: requests allowed per visitor per minute. */
_n( 'Guest chat is enabled with %s request per visitor each minute. Confirm AWS Budgets and model pricing.', 'Guest chat is enabled with %s requests per visitor each minute. Confirm AWS Budgets and model pricing.', max( 1, $guest_limit ), 'ai-chat-for-amazon-bedrock' ),
number_format_i18n( max( 1, $guest_limit ) )
)
);
}
/**
* Whether a configured guardrail actually exists and is ready.
*
* Bedrock fails closed here: a wrong identifier makes every request fail with a
* ValidationException, so the chat stops working entirely. Nothing checked it before,
* which meant finding out from a visitor.
*
* @param array $options Plugin settings.
* @return array
*/
private function check_guardrail( $options ) {
$label = __( 'Guardrail', 'ai-chat-for-amazon-bedrock' );
$identifier = isset( $options['guardrail_id'] ) ? trim( (string) $options['guardrail_id'] ) : '';
if ( '' === $identifier ) {
return $this->result( 'guardrail', $label, 'off', __( 'No guardrail is configured, so nothing is filtered by Amazon Bedrock.', 'ai-chat-for-amazon-bedrock' ) );
}
$version = isset( $options['guardrail_version'] ) ? trim( (string) $options['guardrail_version'] ) : '';
$aws = new AI_Chat_Bedrock_AWS();
if ( ! $aws->has_credentials() ) {
return $this->result( 'guardrail', $label, 'warn', __( 'A guardrail is configured but credentials are missing, so it cannot be verified.', 'ai-chat-for-amazon-bedrock' ) );
}
$guardrail = $aws->get_guardrail( $identifier, $version );
if ( is_wp_error( $guardrail ) ) {
return $this->result(
'guardrail',
$label,
'fail',
sprintf(
/* translators: %s: reason the guardrail could not be read. */
__( 'The configured guardrail could not be read, so every chat request will be refused: %s', 'ai-chat-for-amazon-bedrock' ),
$guardrail->get_error_message()
)
);
}
if ( '' !== $guardrail['status'] && 'READY' !== strtoupper( $guardrail['status'] ) ) {
return $this->result(
'guardrail',
$label,
'warn',
sprintf(
/* translators: 1: guardrail name, 2: guardrail status reported by AWS. */
__( 'Guardrail "%1$s" is %2$s rather than READY.', 'ai-chat-for-amazon-bedrock' ),
$guardrail['name'],
$guardrail['status']
)
);
}
return $this->result(
'guardrail',
$label,
'pass',
sprintf(
/* translators: 1: guardrail name, 2: guardrail version. */
__( 'Guardrail "%1$s" is ready, version %2$s.', 'ai-chat-for-amazon-bedrock' ),
$guardrail['name'],
'' !== $guardrail['version'] ? $guardrail['version'] : 'DRAFT'
)
);
}
/**
* Whether a configured knowledge base ID can work.
*
* The identifier has a fixed shape, so an obvious typo is caught without calling AWS at
* all. Anything that could be real is then tried for real, since a plausible but wrong
* ID otherwise fails silently the first time a visitor asks something.
*
* @param array $options Plugin settings.
* @return array
*/
private function check_knowledge_base( $options ) {
$label = __( 'Knowledge base', 'ai-chat-for-amazon-bedrock' );
$id = isset( $options['knowledge_base_id'] ) ? trim( (string) $options['knowledge_base_id'] ) : '';
if ( '' === $id ) {
return $this->result( 'knowledge_base', $label, 'off', __( 'No Amazon Bedrock knowledge base is configured.', 'ai-chat-for-amazon-bedrock' ) );
}
// AWS requires ten alphanumeric characters, or a knowledge base ARN.
if ( ! preg_match( '#^[0-9a-zA-Z]{10}$#', $id ) && ! preg_match( '#^arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:[0-9]{12}:knowledge-base/[0-9a-zA-Z]{10}$#', $id ) ) {
return $this->result(
'knowledge_base',
$label,
'fail',
__( 'The knowledge base ID is not the right shape. AWS expects ten letters or digits, or a knowledge base ARN.', 'ai-chat-for-amazon-bedrock' )
);
}
$aws = new AI_Chat_Bedrock_AWS();
if ( ! $aws->has_credentials() ) {
return $this->result( 'knowledge_base', $label, 'warn', __( 'A knowledge base is configured but credentials are missing, so it cannot be verified.', 'ai-chat-for-amazon-bedrock' ) );
}
$result = $aws->retrieve_from_knowledge_base( $id, 'test', 1 );
if ( is_wp_error( $result ) ) {
return $this->result(
'knowledge_base',
$label,
'fail',
sprintf(
/* translators: %s: reason the knowledge base could not be queried. */
__( 'The knowledge base could not be queried: %s', 'ai-chat-for-amazon-bedrock' ),
$result->get_error_message()
)
);
}
return $this->result( 'knowledge_base', $label, 'pass', __( 'The knowledge base answered a test query.', 'ai-chat-for-amazon-bedrock' ) );
}
/**
* Whether the semantic search index can be used.
*
* @param array $options Plugin settings.
* @return array
*/
private function check_vector_store( $options ) {
$label = __( 'Semantic search index', 'ai-chat-for-amazon-bedrock' );
$model = isset( $options['embedding_model_id'] ) ? (string) $options['embedding_model_id'] : '';
if ( '' === $model || ! class_exists( 'AI_Chat_Bedrock_Embeddings' ) ) {
return $this->result( 'vector_store', $label, 'off', __( 'Semantic search is off; answers use keyword search.', 'ai-chat-for-amazon-bedrock' ) );
}
if ( 's3_vectors' !== AI_Chat_Bedrock_Embeddings::store( $options ) ) {
$status = AI_Chat_Bedrock_Embeddings::status( $model );
if ( (int) $status['total'] > AI_Chat_Bedrock_Embeddings::MAX_CANDIDATES ) {
return $this->result(
'vector_store',
$label,
'warn',
sprintf(
/* translators: 1: published item count, 2: items compared per question. */
__( 'Vectors are stored in the WordPress database, which compares a question with %2$s of the %1$s published items. Amazon S3 Vectors searches all of them.', 'ai-chat-for-amazon-bedrock' ),
number_format_i18n( (int) $status['total'] ),
number_format_i18n( AI_Chat_Bedrock_Embeddings::MAX_CANDIDATES )
)
);
}
return $this->result( 'vector_store', $label, 'pass', __( 'Vectors are stored in the WordPress database.', 'ai-chat-for-amazon-bedrock' ) );
}
if ( ! AI_Chat_Bedrock_S3_Vectors::enabled( $options ) ) {
return $this->result( 'vector_store', $label, 'fail', __( 'Amazon S3 Vectors is chosen, but the bucket or index name is missing, so semantic search is off.', 'ai-chat-for-amazon-bedrock' ) );
}
$index = AI_Chat_Bedrock_S3_Vectors::describe_index( $model, $options );
if ( is_wp_error( $index ) ) {
return $this->result(
'vector_store',
$label,
'fail',
sprintf(
/* translators: %s: reason the index could not be read. */
__( 'The S3 Vectors index could not be read: %s', 'ai-chat-for-amazon-bedrock' ),
$index->get_error_message()
)
);
}
if ( ! empty( $index['problems'] ) ) {
return $this->result( 'vector_store', $label, 'fail', AI_Chat_Bedrock_Translation::sentences( ...$index['problems'] ) );
}
$message = __( 'The S3 Vectors index exists and matches the embedding model.', 'ai-chat-for-amazon-bedrock' );
if ( 'classic' === $index['mode'] ) {
$message = AI_Chat_Bedrock_Translation::sentences( $message, __( 'It is a CLASSIC index, which applies metadata filters during the similarity search. The plugin asks for filtering first on every query; to make that the index default, switch it to ENHANCED with UpdateIndexMode.', 'ai-chat-for-amazon-bedrock' ) );
}
return $this->result( 'vector_store', $label, 'pass', $message );
}
/**
* Whether WordPress runs the plugin's background tasks on time.
*
* Scheduled WeChat drafts, YouTube uploads, indexing and clean-ups run through WP-Cron,
* which runs only when someone visits and which a page cache or DISABLE_WP_CRON without a
* server cron job can stop altogether. Nothing failed then, so nothing said so.
*
* @return array
*/
private function check_schedules() {
$label = __( 'Background tasks', 'ai-chat-for-amazon-bedrock' );
$late = 0;
$oldest = 0;
$cutoff = time() - 15 * MINUTE_IN_SECONDS;
foreach ( (array) ( function_exists( 'wp_get_ready_cron_jobs' ) ? wp_get_ready_cron_jobs() : array() ) as $time => $hooks ) {
foreach ( (array) $hooks as $hook => $events ) {
if ( 0 === strpos( (string) $hook, 'ai_chat_bedrock_' ) && (int) $time < $cutoff ) {
$late += count( (array) $events );
$oldest = $oldest ? min( $oldest, (int) $time ) : (int) $time;
}
}
}
if ( $late > 0 ) {
$advice = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON
? __( 'WP-Cron is turned off with DISABLE_WP_CRON, so a server cron job has to call wp-cron.php, or run wp cron event run --due-now, every few minutes.', 'ai-chat-for-amazon-bedrock' )
: __( 'WP-Cron runs only when someone visits, and a page cache can keep it from running. Have a server cron job call wp-cron.php every few minutes, then set DISABLE_WP_CRON.', 'ai-chat-for-amazon-bedrock' );
return $this->result(
'schedules',
$label,
'warn',
AI_Chat_Bedrock_Translation::sentences(
sprintf(
/* translators: 1: number of tasks, 2: how long ago the oldest was due, such as 3 hours. */
_n( '%1$s background task is overdue, by %2$s.', '%1$s background tasks are overdue, the oldest by %2$s.', $late, 'ai-chat-for-amazon-bedrock' ),
number_format_i18n( $late ),
human_time_diff( $oldest, time() )
),
$advice
)
);
}
// The recurring tasks, by name, so the check needs none of their classes loaded.
foreach ( array( 'ai_chat_bedrock_wechat_drafts', 'ai_chat_bedrock_index_embeddings', 'ai_chat_bedrock_prune_leads', 'ai_chat_bedrock_prune_chat_history' ) as $hook ) {
if ( wp_next_scheduled( $hook ) ) {
return $this->result( 'schedules', $label, 'pass', __( 'The plugin\'s background tasks run on time.', 'ai-chat-for-amazon-bedrock' ) );
}
}
return $this->result( 'schedules', $label, 'off', __( 'No background tasks are scheduled.', 'ai-chat-for-amazon-bedrock' ) );
}
private function check_mcp() {
if ( ! get_option( 'ai_chat_bedrock_enable_mcp', false ) ) {
return $this->result( 'mcp', __( 'MCP tools', 'ai-chat-for-amazon-bedrock' ), 'off', __( 'MCP tools are disabled.', 'ai-chat-for-amazon-bedrock' ) );
}
if ( get_option( 'ai_chat_bedrock_mcp_public_access', false ) ) {
return $this->result( 'mcp', __( 'MCP tools', 'ai-chat-for-amazon-bedrock' ), 'warn', __( 'The built-in WordPress MCP endpoint is publicly readable. Disable public access unless it is required.', 'ai-chat-for-amazon-bedrock' ) );
}
return $this->result( 'mcp', __( 'MCP tools', 'ai-chat-for-amazon-bedrock' ), 'pass', __( 'MCP tools are enabled and require authentication.', 'ai-chat-for-amazon-bedrock' ) );
}
/**
* What is turned on for AI agents and tools, in one line, with where to turn the rest on.
* It reports the settings, not whether each address answers right now. The MCP check above
* already warns about public access, so this one only reports.
*/
private function check_agents() {
$surface = AI_Chat_Bedrock_Ontology::agent_surface();
$label = __( 'AI agents', 'ai-chat-for-amazon-bedrock' );
$on = array();
$public = false;
if ( $surface['site_description']['on'] ) {
$on[] = __( 'the site description', 'ai-chat-for-amazon-bedrock' );
$public = true;
}
if ( $surface['site_abilities']['on'] ) {
$on[] = __( 'the site content abilities', 'ai-chat-for-amazon-bedrock' );
$public = true;
}
$file = '';
if ( $surface['llms_txt']['on'] && ! $surface['llms_txt']['file'] ) {
/* translators: %s: the llms.txt address. */
$on[] = sprintf( __( 'llms.txt at %s', 'ai-chat-for-amazon-bedrock' ), $surface['llms_txt']['url'] );
$public = true;
} elseif ( $surface['llms_txt']['file'] ) {
$file = __( 'An llms.txt file at the site root, not written by this plugin, is served to AI tools.', 'ai-chat-for-amazon-bedrock' );
}
// The MCP server answers with its own sign-in and tool permissions, so it is listed with
// how it is reached, and the public-content rule is not claimed for it.
if ( $surface['mcp']['on'] ) {
$on[] = $surface['mcp']['public'] ? __( 'the WordPress MCP server, readable without signing in', 'ai-chat-for-amazon-bedrock' ) : __( 'the WordPress MCP server, for signed-in accounts', 'ai-chat-for-amazon-bedrock' );
}
if ( empty( $on ) ) {
return $this->result( 'agents', $label, 'off', AI_Chat_Bedrock_Translation::sentences( __( 'AI agents and tools get nothing from the plugin. The site description, llms.txt, site content abilities and the MCP server are under Settings > Agents and tools.', 'ai-chat-for-amazon-bedrock' ), $file ) );
}
return $this->result(
'agents',
$label,
'pass',
AI_Chat_Bedrock_Translation::sentences(
/* translators: %s: what is turned on, such as "the site description, llms.txt at https://example.com/llms.txt". */
sprintf( __( 'Turned on for AI agents and tools: %s.', 'ai-chat-for-amazon-bedrock' ), AI_Chat_Bedrock_Translation::items( $on ) ),
$public ? __( 'The site description, the site content abilities and the plugin\'s llms.txt show only published, public content, never drafts or members-only text.', 'ai-chat-for-amazon-bedrock' ) : '',
$file
)
);
}
private function check_live_invocation( $options ) {
$aws = new AI_Chat_Bedrock_AWS();
$result = $aws->test_model_access( isset( $options['model_id'] ) ? $options['model_id'] : '' );
if ( empty( $result['success'] ) ) {
return $this->result( 'invocation', __( 'Model invocation', 'ai-chat-for-amazon-bedrock' ), 'fail', $result['message'] );
}
$message = $result['message'];
if ( isset( $result['duration'] ) ) {
/* translators: %d: round trip duration in milliseconds. */
$message = AI_Chat_Bedrock_Translation::sentences( $message, sprintf( __( 'Round trip took %d ms.', 'ai-chat-for-amazon-bedrock' ), (int) $result['duration'] ) );
}
if ( isset( $result['usage']['input_tokens'], $result['usage']['output_tokens'] ) ) {
$message = AI_Chat_Bedrock_Translation::sentences(
$message,
sprintf(
/* translators: 1: input token count, 2: output token count. */
__( 'Tokens used: %1$d input, %2$d output.', 'ai-chat-for-amazon-bedrock' ),
(int) $result['usage']['input_tokens'],
(int) $result['usage']['output_tokens']
)
);
}
return $this->result( 'invocation', __( 'Model invocation', 'ai-chat-for-amazon-bedrock' ), 'pass', $message );
}
private function result( $id, $label, $status, $message ) {
return array(
'id' => sanitize_key( $id ),
'label' => $label,
'status' => in_array( $status, array( 'pass', 'off', 'warn', 'fail' ), true ) ? $status : 'warn',
'message' => $message,
);
}
}