This commit is contained in:
team 1
2026-05-09 11:43:13 +02:00
parent c327dc4102
commit bd62248c8d
6 changed files with 567 additions and 239 deletions

View File

@@ -13,6 +13,7 @@ final class AgentRunnerConfig
private readonly array $config = [],
private readonly ?DomainVocabularyConfig $vocabulary = null,
private readonly ?GenreConfig $genreConfig = null,
private readonly ?ChatMessagesConfig $chatMessages = null,
) {
}
@@ -186,7 +187,7 @@ final class AgentRunnerConfig
public function getInputNormalizationHeartbeatMessage(): string
{
return $this->getRequiredString('input_normalization.heartbeat_message');
return $this->getChatRequiredString('agent.input_normalization.heartbeat_message', 'input_normalization.heartbeat_message');
}
public function getInputNormalizationOutputPrefixPattern(): string
@@ -376,6 +377,41 @@ final class AgentRunnerConfig
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be a non-empty string.', $key));
}
private function getChatRequiredString(string $chatKey, string $legacyKey): string
{
if ($this->chatMessages !== null) {
return $this->chatMessages->getString($chatKey);
}
return $this->getRequiredString($legacyKey);
}
private function getChatStringAllowEmpty(string $chatKey, string $legacyKey): string
{
if ($this->chatMessages !== null) {
return $this->chatMessages->getStringAllowEmpty($chatKey);
}
$value = $this->requiredValue($legacyKey);
if (is_string($value)) {
return $value;
}
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be a string.', $legacyKey));
}
/**
* @return array<int, array{label:string, prompt:string}>
*/
private function getChatActionList(string $chatKey, string $legacyKey): array
{
if ($this->chatMessages !== null) {
return $this->chatMessages->getActionList($chatKey);
}
return $this->getRequiredActionList($legacyKey);
}
private function getOptionalBool(string $key, bool $default): bool
{
$value = $this->optionalValue($key);
@@ -677,52 +713,52 @@ final class AgentRunnerConfig
public function getEmptyPromptMessage(): string
{
return $this->getRequiredString('messages.empty_prompt');
return $this->getChatRequiredString('agent.messages.empty_prompt', 'messages.empty_prompt');
}
public function getAnalyzeRequestMessage(): string
{
return $this->getRequiredString('messages.analyze_request');
return $this->getChatRequiredString('agent.messages.analyze_request', 'messages.analyze_request');
}
public function getCheckInternetSourcesMessage(): string
{
return $this->getRequiredString('messages.check_internet_sources');
return $this->getChatRequiredString('agent.messages.check_internet_sources', 'messages.check_internet_sources');
}
public function getRetrieveKnowledgeMessage(): string
{
return $this->getRequiredString('messages.retrieve_knowledge');
return $this->getChatRequiredString('agent.messages.retrieve_knowledge', 'messages.retrieve_knowledge');
}
public function getOptimizeSearchMessage(): string
{
return $this->getRequiredString('messages.optimize_search');
return $this->getChatRequiredString('agent.messages.optimize_search', 'messages.optimize_search');
}
public function getNoConcreteShopQueryMessage(): string
{
return $this->getRequiredString('messages.no_concrete_shop_query');
return $this->getChatRequiredString('agent.messages.no_concrete_shop_query', 'messages.no_concrete_shop_query');
}
public function getFetchSearchDataMessageTemplate(): string
{
return $this->getRequiredString('messages.fetch_search_data_template');
return $this->getChatRequiredString('agent.messages.fetch_search_data_template', 'messages.fetch_search_data_template');
}
public function getAnalyzeAllInformationMessage(): string
{
return $this->getRequiredString('messages.analyze_all_information');
return $this->getChatRequiredString('agent.messages.analyze_all_information', 'messages.analyze_all_information');
}
public function getThinkingWhileStreamingMessage(): string
{
return $this->getRequiredString('messages.thinking_while_streaming');
return $this->getChatRequiredString('agent.messages.thinking_while_streaming', 'messages.thinking_while_streaming');
}
public function getNoLlmDataReceivedMessage(): string
{
return $this->getRequiredString('messages.no_llm_data_received');
return $this->getChatRequiredString('agent.messages.no_llm_data_received', 'messages.no_llm_data_received');
}
public function isFinalAnswerGuardEnabled(): bool
@@ -737,7 +773,7 @@ final class AgentRunnerConfig
public function getFinalAnswerGuardTruncationMessage(): string
{
return $this->getRequiredString('final_answer_guard.truncation_message');
return $this->getChatRequiredString('agent.final_answer_guard.truncation_message', 'final_answer_guard.truncation_message');
}
public function isFinalAnswerRepeatedLineGuardEnabled(): bool
@@ -788,31 +824,31 @@ final class AgentRunnerConfig
public function getDirectShopResultAnswerIntro(): string
{
return $this->genreString('shop_query_runtime.direct_answer.intro')
?: $this->getRequiredString('shop_runtime.direct_answer.intro');
?: $this->getChatStringAllowEmpty('agent.shop_runtime.direct_answer.intro', 'shop_runtime.direct_answer.intro');
}
public function getDirectShopResultAnswerNoResultsMessage(): string
{
return $this->genreString('shop_query_runtime.direct_answer.no_results')
?: $this->getRequiredString('shop_runtime.direct_answer.no_results');
?: $this->getChatStringAllowEmpty('agent.shop_runtime.direct_answer.no_results', 'shop_runtime.direct_answer.no_results');
}
public function getDirectShopResultAnswerSortedByLengthNote(): string
{
return $this->genreString('shop_query_runtime.direct_answer.sorted_by_length_note')
?: $this->getRequiredString('shop_runtime.direct_answer.sorted_by_length_note');
?: $this->getChatStringAllowEmpty('agent.shop_runtime.direct_answer.sorted_by_length_note', 'shop_runtime.direct_answer.sorted_by_length_note');
}
public function getDirectShopResultAnswerMinLengthFilterNote(): string
{
return $this->genreString('shop_query_runtime.direct_answer.min_length_filter_note')
?: $this->getRequiredString('shop_runtime.direct_answer.min_length_filter_note');
?: $this->getChatStringAllowEmpty('agent.shop_runtime.direct_answer.min_length_filter_note', 'shop_runtime.direct_answer.min_length_filter_note');
}
public function getDirectShopResultAnswerMaxLengthFilterNote(): string
{
return $this->genreString('shop_query_runtime.direct_answer.max_length_filter_note')
?: $this->getRequiredString('shop_runtime.direct_answer.max_length_filter_note');
?: $this->getChatStringAllowEmpty('agent.shop_runtime.direct_answer.max_length_filter_note', 'shop_runtime.direct_answer.max_length_filter_note');
}
public function getNoLlmFallbackMaxShopResults(): int
@@ -870,63 +906,63 @@ final class AgentRunnerConfig
public function getNoLlmFallbackShopOnlyMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.shop_only');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.shop_only', 'no_llm_fallback.messages.shop_only');
}
public function getNoLlmFallbackShopWithKnowledgeMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.shop_with_knowledge');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.shop_with_knowledge', 'no_llm_fallback.messages.shop_with_knowledge');
}
public function getNoLlmFallbackAccessoryOnlyForMainDeviceMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.accessory_only_for_main_device');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.accessory_only_for_main_device', 'no_llm_fallback.messages.accessory_only_for_main_device');
}
public function getNoLlmFallbackEscalationMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.escalation');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.escalation', 'no_llm_fallback.messages.escalation');
}
public function getNoLlmFallbackKnowledgeOnlyMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.knowledge_only');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.knowledge_only', 'no_llm_fallback.messages.knowledge_only');
}
public function getNoLlmFallbackNoDataMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.no_data');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.no_data', 'no_llm_fallback.messages.no_data');
}
public function getShopRepairCheckMessage(): string
{
return $this->getRequiredString('messages.shop_repair_check');
return $this->getChatRequiredString('agent.messages.shop_repair_check', 'messages.shop_repair_check');
}
public function getShopQueryOptimizationHeartbeatMessage(): string
{
return $this->getRequiredString('messages.shop_query_optimization_heartbeat');
return $this->getChatRequiredString('agent.messages.shop_query_optimization_heartbeat', 'messages.shop_query_optimization_heartbeat');
}
public function getProductionUiStageLabel(string $key): string
{
return $this->getRequiredString('production_ui.stage_labels.' . $key);
return $this->getChatRequiredString('agent.production_ui.stage_labels.' . $key, 'production_ui.stage_labels.' . $key);
}
public function getProductionUiConfidenceLabel(string $key): string
{
return $this->getRequiredString('production_ui.confidence_labels.' . $key);
return $this->getChatRequiredString('agent.production_ui.confidence_labels.' . $key, 'production_ui.confidence_labels.' . $key);
}
public function getProductionUiText(string $key): string
{
return $this->getRequiredString('production_ui.text.' . $key);
return $this->getChatRequiredString('agent.production_ui.text.' . $key, 'production_ui.text.' . $key);
}
public function getProductionUiTemplate(string $key): string
{
return $this->getRequiredString('production_ui.templates.' . $key);
return $this->getChatRequiredString('agent.production_ui.templates.' . $key, 'production_ui.templates.' . $key);
}
public function getProductionUiShopResultsMaxCards(): int
@@ -939,22 +975,22 @@ final class AgentRunnerConfig
*/
public function getProductionUiFollowUpActions(string $group): array
{
return $this->getRequiredActionList('production_ui.follow_up_actions.' . $group);
return $this->getChatActionList('agent.production_ui.follow_up_actions.' . $group, 'production_ui.follow_up_actions.' . $group);
}
public function getNoLlmProductField(string $key): string
{
return $this->getRequiredString('no_llm_fallback.product_fields.' . $key);
return $this->getChatRequiredString('agent.no_llm_fallback.product_fields.' . $key, 'no_llm_fallback.product_fields.' . $key);
}
public function getNoLlmFallbackNoShopResultsWithKnowledgeMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.no_shop_results_with_knowledge');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.no_shop_results_with_knowledge', 'no_llm_fallback.messages.no_shop_results_with_knowledge');
}
public function getNoLlmFallbackNoShopResultsNoKnowledgeMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.no_shop_results_no_knowledge');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.no_shop_results_no_knowledge', 'no_llm_fallback.messages.no_shop_results_no_knowledge');
}
/**
@@ -991,82 +1027,82 @@ final class AgentRunnerConfig
public function getNoLlmFallbackShopUnavailableWithKnowledgeMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.shop_unavailable_with_knowledge');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.shop_unavailable_with_knowledge', 'no_llm_fallback.messages.shop_unavailable_with_knowledge');
}
public function getNoLlmFallbackShopUnavailableNoKnowledgeMessage(): string
{
return $this->getRequiredString('no_llm_fallback.messages.shop_unavailable_no_knowledge');
return $this->getChatRequiredString('agent.no_llm_fallback.messages.shop_unavailable_no_knowledge', 'no_llm_fallback.messages.shop_unavailable_no_knowledge');
}
public function getGenericInternalErrorMessage(): string
{
return $this->getRequiredString('messages.generic_internal_error');
return $this->getChatRequiredString('agent.messages.generic_internal_error', 'messages.generic_internal_error');
}
public function getDebugInternalErrorPrefix(): string
{
return $this->getRequiredString('messages.debug_internal_error_prefix');
return $this->getChatRequiredString('agent.messages.debug_internal_error_prefix', 'messages.debug_internal_error_prefix');
}
public function getExternalUrlSourceLabel(): string
{
return $this->getRequiredString('source_labels.external_url');
return $this->getChatRequiredString('agent.source_labels.external_url', 'source_labels.external_url');
}
public function getRagKnowledgeSourceLabel(): string
{
return $this->getRequiredString('source_labels.rag_knowledge');
return $this->getChatRequiredString('agent.source_labels.rag_knowledge', 'source_labels.rag_knowledge');
}
public function getConversationHistorySourceLabel(): string
{
return $this->getRequiredString('source_labels.conversation_history');
return $this->getChatRequiredString('agent.source_labels.conversation_history', 'source_labels.conversation_history');
}
public function getShopSystemSourceLabel(): string
{
return $this->getRequiredString('source_labels.shop_system');
return $this->getChatRequiredString('agent.source_labels.shop_system', 'source_labels.shop_system');
}
public function getExtendedShopSearchSourceLabel(): string
{
return $this->getRequiredString('source_labels.extended_shop_search');
return $this->getChatRequiredString('agent.source_labels.extended_shop_search', 'source_labels.extended_shop_search');
}
public function getUsedSourcesPrefix(): string
{
return $this->getRequiredString('source_labels.used_sources_prefix');
return $this->getChatRequiredString('agent.source_labels.used_sources_prefix', 'source_labels.used_sources_prefix');
}
public function getSourcesPrefix(): string
{
return $this->getRequiredString('source_labels.sources_prefix');
return $this->getChatRequiredString('agent.source_labels.sources_prefix', 'source_labels.sources_prefix');
}
public function getSourceBadgeHtmlTemplate(): string
{
return $this->getRequiredString('html.source_badge_template');
return $this->getChatRequiredString('agent.html.source_badge_template', 'html.source_badge_template');
}
public function getErrorHtmlTemplate(): string
{
return $this->getRequiredString('html.error_template');
return $this->getChatRequiredString('agent.html.error_template', 'html.error_template');
}
public function getThinkHtmlTemplate(): string
{
return $this->getRequiredString('html.think_template');
return $this->getChatRequiredString('agent.html.think_template', 'html.think_template');
}
public function getInfoHtmlTemplate(): string
{
return $this->getRequiredString('html.info_template');
return $this->getChatRequiredString('agent.html.info_template', 'html.info_template');
}
public function getDebugHtmlTemplate(): string
{
return $this->getRequiredString('html.debug_template');
return $this->getChatRequiredString('agent.html.debug_template', 'html.debug_template');
}
public function getShopPrompt(string $prompt, string $commerceHistoryContext = ''): string
{

View File

@@ -156,6 +156,30 @@ final class ChatMessagesConfig
throw new \InvalidArgumentException('RetrieX chat messages config key "frontend" must be an array.');
}
public function getString(string $path): string
{
return $this->string($path);
}
public function getStringAllowEmpty(string $path): string
{
$value = $this->value($path);
if (is_string($value)) {
return $value;
}
throw new \InvalidArgumentException(sprintf('RetrieX chat messages config key "%s" must be a string.', $path));
}
/**
* @return array<int, array{label:string, prompt:string}>
*/
public function getActionList(string $path): array
{
return $this->actionList($path);
}
/**
* @return array<string, mixed>
*/
@@ -187,6 +211,14 @@ final class ChatMessagesConfig
}
}
foreach ($this->requiredActionListPaths() as $path) {
try {
$this->actionList($path);
} catch (\InvalidArgumentException $e) {
$errors[] = $e->getMessage();
}
}
return [
'status' => $errors === [] ? 'OK' : 'ERROR',
'errors' => $errors,
@@ -251,6 +283,165 @@ final class ChatMessagesConfig
'frontend.stream.missing_retry',
'frontend.stream.stale_retry',
'frontend.stream.connection_interrupted_retry',
'agent.input_normalization.heartbeat_message',
'agent.messages.empty_prompt',
'agent.messages.analyze_request',
'agent.messages.check_internet_sources',
'agent.messages.retrieve_knowledge',
'agent.messages.optimize_search',
'agent.messages.no_concrete_shop_query',
'agent.messages.fetch_search_data_template',
'agent.messages.analyze_all_information',
'agent.messages.thinking_while_streaming',
'agent.messages.no_llm_data_received',
'agent.messages.shop_repair_check',
'agent.messages.shop_query_optimization_heartbeat',
'agent.messages.generic_internal_error',
'agent.messages.debug_internal_error_prefix',
'agent.final_answer_guard.truncation_message',
'agent.no_llm_fallback.messages.shop_only',
'agent.no_llm_fallback.messages.shop_with_knowledge',
'agent.no_llm_fallback.messages.accessory_only_for_main_device',
'agent.no_llm_fallback.messages.escalation',
'agent.no_llm_fallback.messages.knowledge_only',
'agent.no_llm_fallback.messages.no_data',
'agent.no_llm_fallback.messages.no_shop_results_with_knowledge',
'agent.no_llm_fallback.messages.no_shop_results_no_knowledge',
'agent.no_llm_fallback.messages.shop_unavailable_with_knowledge',
'agent.no_llm_fallback.messages.shop_unavailable_no_knowledge',
'agent.no_llm_fallback.product_fields.unreadable_results_message',
'agent.no_llm_fallback.product_fields.unnamed_product',
'agent.no_llm_fallback.product_fields.product_number_template',
'agent.no_llm_fallback.product_fields.manufacturer_template',
'agent.no_llm_fallback.product_fields.price_template',
'agent.no_llm_fallback.product_fields.availability_template',
'agent.no_llm_fallback.product_fields.availability_yes',
'agent.no_llm_fallback.product_fields.availability_no',
'agent.no_llm_fallback.product_fields.url_template',
'agent.no_llm_fallback.product_fields.incompatible_role_note',
'agent.no_llm_fallback.product_fields.line_template',
'agent.no_llm_fallback.product_fields.separator',
'agent.no_llm_fallback.product_fields.unavailable_reason_template',
'agent.production_ui.stage_labels.preparing_answer',
'agent.production_ui.stage_labels.shop_routing_detected',
'agent.production_ui.stage_labels.rag_searched',
'agent.production_ui.stage_labels.shop_search_preparing',
'agent.production_ui.stage_labels.more_context_needed',
'agent.production_ui.stage_labels.shop_search_running',
'agent.production_ui.stage_labels.shop_unavailable',
'agent.production_ui.stage_labels.shop_completed',
'agent.production_ui.stage_labels.answer_generating',
'agent.production_ui.stage_labels.completed',
'agent.production_ui.stage_labels.interrupted',
'agent.production_ui.confidence_labels.checking_evidence',
'agent.production_ui.confidence_labels.checking_shop_data',
'agent.production_ui.confidence_labels.more_context_needed',
'agent.production_ui.confidence_labels.interrupted',
'agent.production_ui.confidence_labels.direct',
'agent.production_ui.confidence_labels.aggregate_missing',
'agent.production_ui.confidence_labels.weak',
'agent.production_ui.confidence_labels.default',
'agent.production_ui.confidence_labels.direct_shop_check',
'agent.production_ui.confidence_labels.aggregate_missing_shop_check',
'agent.production_ui.confidence_labels.weak_shop_check',
'agent.production_ui.confidence_labels.default_shop_check',
'agent.production_ui.confidence_labels.aggregate_missing_shop_unavailable',
'agent.production_ui.confidence_labels.aggregate_missing_no_count',
'agent.production_ui.confidence_labels.shop_unavailable_with_knowledge',
'agent.production_ui.confidence_labels.shop_unavailable',
'agent.production_ui.confidence_labels.rag_and_shop',
'agent.production_ui.confidence_labels.shop_only',
'agent.production_ui.confidence_labels.rag_no_shop_hits',
'agent.production_ui.confidence_labels.no_reliable_data',
'agent.production_ui.confidence_labels.no_reliable_hits',
'agent.production_ui.text.live_shop_source_plain_label',
'agent.production_ui.text.run_status_eyebrow',
'agent.production_ui.text.evidence_prefix',
'agent.production_ui.text.data_basis_label',
'agent.production_ui.text.data_basis_empty_completed',
'agent.production_ui.text.data_basis_empty_running',
'agent.production_ui.text.rag_hits_checking',
'agent.production_ui.text.shop_hits_loading',
'agent.production_ui.text.shop_hits_unavailable',
'agent.production_ui.text.shop_hits_no_query',
'agent.production_ui.text.shop_hits_not_requested',
'agent.production_ui.text.status_completed',
'agent.production_ui.text.status_running',
'agent.production_ui.text.shop_results_eyebrow',
'agent.production_ui.text.shop_results_title',
'agent.production_ui.text.evaluated_query_label',
'agent.production_ui.text.unnamed_product',
'agent.production_ui.text.field_not_provided',
'agent.production_ui.text.product_number_label',
'agent.production_ui.text.price_label',
'agent.production_ui.text.availability_label',
'agent.production_ui.text.manufacturer_label',
'agent.production_ui.text.relevance_label',
'agent.production_ui.text.availability_yes',
'agent.production_ui.text.availability_no',
'agent.production_ui.text.availability_unknown',
'agent.production_ui.text.followup_eyebrow',
'agent.production_ui.text.followup_title',
'agent.production_ui.text.shop_meta_fallback_query',
'agent.production_ui.text.shop_meta_query_mode_optimized',
'agent.production_ui.text.shop_meta_query_mode_direct',
'agent.production_ui.text.shop_meta_default_intent',
'agent.production_ui.text.shop_meta_title_unavailable',
'agent.production_ui.text.shop_meta_title_completed',
'agent.production_ui.text.shop_meta_title_running',
'agent.production_ui.text.shop_meta_status_completed',
'agent.production_ui.text.shop_meta_status_running',
'agent.production_ui.text.shop_meta_result_unavailable',
'agent.production_ui.text.shop_meta_result_loading',
'agent.production_ui.text.shop_meta_repair_used',
'agent.production_ui.text.shop_meta_repair_checked',
'agent.production_ui.text.shop_meta_eyebrow',
'agent.production_ui.text.shop_meta_query_label',
'agent.production_ui.text.shop_meta_query_prefix',
'agent.production_ui.text.shop_meta_intent_prefix',
'agent.production_ui.text.shop_unavailable_default_reason',
'agent.production_ui.text.shop_unavailable_title',
'agent.production_ui.text.shop_unavailable_text_prefix',
'agent.production_ui.text.no_llm_history_default',
'agent.production_ui.text.history_notice_default_title',
'agent.production_ui.text.history_notice_shop_unavailable_title',
'agent.production_ui.text.history_notice_answer_incomplete_title',
'agent.production_ui.templates.rag_hits_count',
'agent.production_ui.templates.shop_hits_count',
'agent.production_ui.templates.shop_results_summary',
'agent.production_ui.templates.shop_results_top_displayed_suffix',
'agent.production_ui.templates.shop_results_repair_suffix',
'agent.production_ui.templates.relevance_matched_queries',
'agent.production_ui.templates.relevance_highlight',
'agent.production_ui.templates.relevance_match_source',
'agent.production_ui.templates.relevance_query',
'agent.production_ui.templates.relevance_default',
'agent.production_ui.templates.shop_meta_result_count',
'agent.production_ui.templates.history_notice_without_detail',
'agent.production_ui.templates.history_notice_with_detail',
'agent.source_labels.external_url',
'agent.source_labels.rag_knowledge',
'agent.source_labels.conversation_history',
'agent.source_labels.shop_system',
'agent.source_labels.extended_shop_search',
'agent.source_labels.used_sources_prefix',
'agent.source_labels.sources_prefix',
'agent.html.source_badge_template',
'agent.html.error_template',
'agent.html.think_template',
'agent.html.info_template',
'agent.html.debug_template',
];
}
/**
* @return list<string>
*/
private function requiredActionListPaths(): array
{
return [
'agent.production_ui.follow_up_actions.commerce',
'agent.production_ui.follow_up_actions.knowledge',
];
}
@@ -296,6 +487,44 @@ final class ChatMessagesConfig
return '';
}
/**
* @return array<int, array{label:string, prompt:string}>
*/
private function actionList(string $path): array
{
$value = $this->value($path);
if (!is_array($value)) {
throw new \InvalidArgumentException(sprintf('RetrieX chat messages config key "%s" must be a list of action definitions.', $path));
}
$out = [];
foreach ($value as $item) {
if (!is_array($item)) {
continue;
}
$label = isset($item['label']) && is_scalar($item['label']) ? trim((string) $item['label']) : '';
$prompt = isset($item['prompt']) && is_scalar($item['prompt']) ? trim((string) $item['prompt']) : '';
if ($label === '' || $prompt === '') {
continue;
}
$out[] = [
'label' => $label,
'prompt' => $prompt,
];
}
if ($out === []) {
throw new \InvalidArgumentException(sprintf('RetrieX chat messages config key "%s" must contain at least one valid action definition.', $path));
}
return $out;
}
/**
* @return list<string>
*/