p36c
This commit is contained in:
@@ -260,26 +260,6 @@ final class AgentRunnerConfig
|
||||
return $this->getRequiredStringList('input_normalization.fuzzy_routing.terms');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getInputNormalizationPlaceholderOutputs(): array
|
||||
{
|
||||
return $this->getRequiredStringList('input_normalization.placeholder_outputs');
|
||||
}
|
||||
|
||||
/** @return array<string, string> */
|
||||
public function getCommerceFollowUpActions(): array
|
||||
{
|
||||
return $this->getRequiredStringMap('followup_actions.commerce');
|
||||
}
|
||||
|
||||
/** @return array<string, string> */
|
||||
public function getKnowledgeFollowUpActions(): array
|
||||
{
|
||||
return $this->getRequiredStringMap('followup_actions.knowledge');
|
||||
}
|
||||
|
||||
private function getRequiredInt(string $key): int
|
||||
{
|
||||
$value = $this->requiredValue($key);
|
||||
@@ -325,6 +305,65 @@ final class AgentRunnerConfig
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be a non-empty string.', $key));
|
||||
}
|
||||
|
||||
private function getOptionalBool(string $key, bool $default): bool
|
||||
{
|
||||
$value = $this->optionalValue($key);
|
||||
|
||||
if ($value === null) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (is_scalar($value)) {
|
||||
$normalized = strtolower(trim((string) $value));
|
||||
|
||||
if (in_array($normalized, ['1', 'true', 'yes', 'on'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($normalized, ['0', 'false', 'no', 'off'], true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be boolean.', $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getOptionalStringList(string $key): array
|
||||
{
|
||||
$value = $this->optionalValue($key);
|
||||
|
||||
if ($value === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be a list.', $key));
|
||||
}
|
||||
|
||||
$out = [];
|
||||
|
||||
foreach ($value as $item) {
|
||||
if (!is_scalar($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = trim((string) $item);
|
||||
|
||||
if ($item !== '') {
|
||||
$out[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($out));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@@ -404,39 +443,6 @@ final class AgentRunnerConfig
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function getRequiredStringMap(string $key): array
|
||||
{
|
||||
$value = $this->requiredValue($key);
|
||||
|
||||
if (!is_array($value)) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must be a string map.', $key));
|
||||
}
|
||||
|
||||
$out = [];
|
||||
|
||||
foreach ($value as $mapKey => $mapValue) {
|
||||
if (!is_scalar($mapKey) || !is_scalar($mapValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapKey = trim((string) $mapKey);
|
||||
$mapValue = trim((string) $mapValue);
|
||||
|
||||
if ($mapKey !== '' && $mapValue !== '') {
|
||||
$out[$mapKey] = $mapValue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($out === []) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX agent config key "%s" must contain at least one valid entry.', $key));
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
@@ -787,6 +793,19 @@ final class AgentRunnerConfig
|
||||
return $this->getRequiredStringList('shop_prompt.context_usage.referential_terms');
|
||||
}
|
||||
|
||||
public function isShopQueryCurrentInputPreservationEnabled(): bool
|
||||
{
|
||||
return $this->getOptionalBool('shop_prompt.current_input_preservation.enabled', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getShopQueryCurrentInputPreservationTerms(): array
|
||||
{
|
||||
return $this->getOptionalStringList('shop_prompt.current_input_preservation.terms');
|
||||
}
|
||||
|
||||
public function getShopPromptIntro(): string
|
||||
{
|
||||
return $this->getRequiredString('shop_prompt.intro');
|
||||
|
||||
@@ -120,6 +120,12 @@ final class GovernanceConfig
|
||||
return $this->requiredStringList('regression_baseline.shop_query_context_fallback_filter_terms');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionShopQueryCurrentInputPreservationTerms(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.shop_query_current_input_preservation_terms');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getVocabularyProtectedShortModelTokens(): array
|
||||
{
|
||||
|
||||
@@ -310,6 +310,20 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
$errors[] = 'Missing shop query context fallback filter term: ' . $term;
|
||||
}
|
||||
}
|
||||
$currentInputPreservationTerms = $this->effectiveShopQueryCurrentInputPreservationTerms();
|
||||
$checks['shop_query_current_input_preservation_enabled'] = $this->agentRunnerConfig->isShopQueryCurrentInputPreservationEnabled();
|
||||
if (!$checks['shop_query_current_input_preservation_enabled']) {
|
||||
$errors[] = 'Shop query current-input term preservation is disabled.';
|
||||
}
|
||||
|
||||
foreach ($this->governanceConfig->getRegressionShopQueryCurrentInputPreservationTerms() as $term) {
|
||||
$key = 'shop_query_current_input_preservation_' . $this->guardrailCheckKey($term);
|
||||
$checks[$key] = in_array($term, $currentInputPreservationTerms, true);
|
||||
if (!$checks[$key]) {
|
||||
$errors[] = 'Missing shop query current-input preservation term: ' . $term;
|
||||
}
|
||||
}
|
||||
|
||||
$checks['shop_query_context_fallback_history_budget_positive'] = $this->agentRunnerConfig->getShopQueryContextFallbackHistoryBudgetChars() > 0;
|
||||
if (!$checks['shop_query_context_fallback_history_budget_positive']) {
|
||||
$errors[] = 'Shop query context fallback history budget must be greater than zero.';
|
||||
@@ -369,6 +383,15 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
);
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function effectiveShopQueryCurrentInputPreservationTerms(): array
|
||||
{
|
||||
return $this->mergeUniqueStrings(
|
||||
$this->languageCleanupConfig->getProtectedTerms(),
|
||||
$this->agentRunnerConfig->getShopQueryCurrentInputPreservationTerms()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $left
|
||||
* @param string[] $right
|
||||
@@ -583,7 +606,6 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
'max_length_ratio_percent' => $this->agentRunnerConfig->getInputNormalizationMaxLengthRatioPercent(),
|
||||
'heartbeat_message' => $this->agentRunnerConfig->getInputNormalizationHeartbeatMessage(),
|
||||
'output_prefix_pattern' => $this->agentRunnerConfig->getInputNormalizationOutputPrefixPattern(),
|
||||
'placeholder_outputs' => $this->agentRunnerConfig->getInputNormalizationPlaceholderOutputs(),
|
||||
'skip_patterns' => $this->agentRunnerConfig->getInputNormalizationSkipPatterns(),
|
||||
'prompt' => [
|
||||
'intro' => $this->agentRunnerConfig->getInputNormalizationIntro(),
|
||||
@@ -603,10 +625,6 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
'terms' => $this->agentRunnerConfig->getInputNormalizationFuzzyRoutingTerms(),
|
||||
],
|
||||
],
|
||||
'followup_actions' => [
|
||||
'commerce' => $this->agentRunnerConfig->getCommerceFollowUpActions(),
|
||||
'knowledge' => $this->agentRunnerConfig->getKnowledgeFollowUpActions(),
|
||||
],
|
||||
'messages' => [
|
||||
'empty_prompt' => $this->agentRunnerConfig->getEmptyPromptMessage(),
|
||||
'analyze_request' => $this->agentRunnerConfig->getAnalyzeRequestMessage(),
|
||||
@@ -660,6 +678,10 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
'context_usage' => [
|
||||
'referential_terms' => $this->agentRunnerConfig->getShopQueryContextUsageReferentialTerms(),
|
||||
],
|
||||
'current_input_preservation' => [
|
||||
'enabled' => $this->agentRunnerConfig->isShopQueryCurrentInputPreservationEnabled(),
|
||||
'terms' => $this->agentRunnerConfig->getShopQueryCurrentInputPreservationTerms(),
|
||||
],
|
||||
'context_anchor_enrichment' => [
|
||||
'enabled' => $this->agentRunnerConfig->isShopQueryContextAnchorEnrichmentEnabled(),
|
||||
'max_query_terms' => $this->agentRunnerConfig->getShopQueryContextAnchorEnrichmentMaxQueryTerms(),
|
||||
@@ -934,9 +956,6 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
return [
|
||||
'stopwords' => $this->stopWordsConfig->getStopWords(),
|
||||
'protected_terms' => $this->languageCleanupConfig->getProtectedTerms(),
|
||||
'normalization' => [
|
||||
'ascii_transliteration' => $this->languageCleanupConfig->getAsciiTransliterationMap(),
|
||||
],
|
||||
'cleanup_profile_names' => $this->languageCleanupConfig->getCleanupProfileNames(),
|
||||
'cleanup_profiles' => $profiles,
|
||||
];
|
||||
@@ -1208,7 +1227,6 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
private function validateAgent(array $agent, array &$errors, array &$warnings): void
|
||||
{
|
||||
$this->validateStringListMap($agent['messages'] ?? [], 'agent.messages', $errors, $warnings);
|
||||
$this->validateStringListMap($agent['followup_actions'] ?? [], 'agent.followup_actions', $errors, $warnings);
|
||||
$this->validateStringListMap($agent['source_labels'] ?? [], 'agent.source_labels', $errors, $warnings);
|
||||
$this->validateStringListMap($agent['html_templates'] ?? [], 'agent.html_templates', $errors, $warnings);
|
||||
|
||||
@@ -1226,9 +1244,6 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
$errors[] = 'agent.follow_up_context.commercial_table_follow_up.query_template_without_model must not be empty.';
|
||||
}
|
||||
|
||||
$inputNormalization = is_array($agent['input_normalization'] ?? null) ? $agent['input_normalization'] : [];
|
||||
$this->validateStringList($this->toList($inputNormalization['placeholder_outputs'] ?? []), 'agent.input_normalization.placeholder_outputs', $errors, $warnings);
|
||||
|
||||
$ragEvidence = is_array($agent['rag_evidence_guard'] ?? null) ? $agent['rag_evidence_guard'] : [];
|
||||
$ragEvidenceCleanupProfile = $ragEvidence['cleanup_profile'] ?? null;
|
||||
if (!is_string($ragEvidenceCleanupProfile) || trim($ragEvidenceCleanupProfile) === '') {
|
||||
@@ -1255,6 +1270,17 @@ final readonly class RetriexEffectiveConfigProvider
|
||||
$errors[] = 'agent.shop_prompt.meta_query_guard.cleanup_profile references unknown language cleanup profile: ' . $shopContextCleanupProfile . '.';
|
||||
}
|
||||
|
||||
$currentInputPreservation = is_array($shopPrompt['current_input_preservation'] ?? null) ? $shopPrompt['current_input_preservation'] : [];
|
||||
if (array_key_exists('enabled', $currentInputPreservation) && !is_bool($currentInputPreservation['enabled'])) {
|
||||
$errors[] = 'agent.shop_prompt.current_input_preservation.enabled must be boolean.';
|
||||
}
|
||||
$this->validateStringList(
|
||||
$this->toList($currentInputPreservation['terms'] ?? []),
|
||||
'agent.shop_prompt.current_input_preservation.terms',
|
||||
$errors,
|
||||
$warnings
|
||||
);
|
||||
|
||||
$this->validateStringListMap($agent['shop_query_optimizer'] ?? [], 'agent.shop_query_optimizer', $errors, $warnings);
|
||||
$this->validateRegexPattern($agent['optimized_shop_query_prefix_pattern'] ?? null, 'agent.optimized_shop_query_prefix_pattern', $errors);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user