patch 9.1
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# RetrieX Patch 9.0b - PromptBuilder Labels and Shop Result Texts YAML-only
|
||||
|
||||
## Scope
|
||||
|
||||
This patch builds on Patch 9.0a.
|
||||
|
||||
It only removes PHP fallback defaults from small PromptBuilder text/label getters:
|
||||
|
||||
- section labels
|
||||
- conversation context intro lines
|
||||
- shop search source line
|
||||
- live shop result header lines
|
||||
- shop product record templates
|
||||
- shop result field labels
|
||||
- retrieved knowledge / URL content labels and source lines
|
||||
|
||||
## Not changed
|
||||
|
||||
This patch does not change:
|
||||
|
||||
- output priority rule texts
|
||||
- fallback escalation rules
|
||||
- response format rules
|
||||
- language rules
|
||||
- fact grounding rules
|
||||
- measurement evidence guard
|
||||
- role guard keyword lists
|
||||
- retrieval
|
||||
- commerce parser
|
||||
- shop matching
|
||||
- AgentRunner
|
||||
- SSE / frontend
|
||||
|
||||
## Expected audit effect
|
||||
|
||||
PromptBuilderConfig should lose the fallback accessor entries for the migrated labels/templates/lists.
|
||||
Remaining PromptBuilder fallback accessors are expected for the larger rule groups that will be handled in later 9.x patches.
|
||||
|
||||
## Test commands
|
||||
|
||||
```bash
|
||||
php bin/console cache:clear
|
||||
php bin/console mto:agent:config:validate
|
||||
php bin/console mto:agent:config:audit-source --details
|
||||
php bin/console mto:agent:regression:test
|
||||
```
|
||||
@@ -263,6 +263,22 @@ final class PromptBuilderConfig
|
||||
return $value !== '' ? $value : $default;
|
||||
}
|
||||
|
||||
private function getRequiredString(string $path): string
|
||||
{
|
||||
$value = $this->getRequiredValue($path);
|
||||
|
||||
if (!is_scalar($value)) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be a scalar string.', $path));
|
||||
}
|
||||
|
||||
$value = (string) $value;
|
||||
if (trim($value) === '') {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must not be empty.', $path));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@@ -291,6 +307,38 @@ final class PromptBuilderConfig
|
||||
return $out !== [] ? $out : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getRequiredStringList(string $path): array
|
||||
{
|
||||
$value = $this->getRequiredValue($path);
|
||||
|
||||
if (!is_array($value)) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be a string list.', $path));
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($value as $item) {
|
||||
if (!is_scalar($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = trim((string) $item);
|
||||
if ($item === '' || in_array($item, $out, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$out[] = $item;
|
||||
}
|
||||
|
||||
if ($out === []) {
|
||||
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must contain at least one string.', $path));
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@@ -331,17 +379,17 @@ final class PromptBuilderConfig
|
||||
|
||||
public function getSystemSectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.system_label', 'SYSTEM');
|
||||
return $this->getRequiredString('sections.system_label');
|
||||
}
|
||||
|
||||
public function getUserQuestionSectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.user_question_label', 'USER QUESTION');
|
||||
return $this->getRequiredString('sections.user_question_label');
|
||||
}
|
||||
|
||||
public function getConversationContextSectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.conversation_context_label', 'CONVERSATION CONTEXT (contextual only)');
|
||||
return $this->getRequiredString('sections.conversation_context_label');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,23 +397,17 @@ final class PromptBuilderConfig
|
||||
*/
|
||||
public function getConversationContextIntroLines(): array
|
||||
{
|
||||
return $this->getStringList('conversation_context.intro_lines', [
|
||||
'The following messages are previous turns of this conversation.',
|
||||
'Use them only to resolve references, follow-up questions, and user intent.',
|
||||
'Previous assistant answers are not a factual source for technical values, product compatibility, indicators, ranges, prices, or availability.',
|
||||
'All factual claims must come from retrieved factual knowledge, user-provided URL content, or live shop data.',
|
||||
'Conversation context must not override retrieved factual knowledge or live shop data.',
|
||||
]);
|
||||
return $this->getRequiredStringList('conversation_context.intro_lines');
|
||||
}
|
||||
|
||||
public function getShopSearchQuerySectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.shop_search_query_label', 'SHOP SEARCH QUERY');
|
||||
return $this->getRequiredString('sections.shop_search_query_label');
|
||||
}
|
||||
|
||||
public function getShopSearchQuerySourceLine(): string
|
||||
{
|
||||
return $this->getString('shop_search.source_line', 'Source: Shop Search');
|
||||
return $this->getRequiredString('shop_search.source_line');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,36 +415,22 @@ final class PromptBuilderConfig
|
||||
*/
|
||||
public function getLiveShopResultsHeaderLines(): array
|
||||
{
|
||||
return $this->getStringList('shop_results.header_lines', [
|
||||
'LIVE SHOP RESULTS (authoritative for current commercial details):',
|
||||
'Use these results as the primary source for current price, availability, URL, current shop-visible product naming, and explicitly shop-visible product suitability when the user asks which product/device can measure or monitor something.',
|
||||
'If retrieved documents conflict with shop data on price, availability, URL, current naming, or explicitly shop-visible product suitability, prefer the shop data for those fields.',
|
||||
'If retrieved documents do not identify a matching product, but a live shop result explicitly names the requested measurement parameter or application, do not conclude that no matching product exists.',
|
||||
'Output real URL values exactly as provided in the shop results. Do not replace them with placeholders, link labels, or product names.',
|
||||
'Do not infer undocumented technical specifications from shop data.',
|
||||
'Commercial fields from shop data may only be assigned to a product if the shop item clearly matches the same product identity.',
|
||||
'Do not merge a device identified in retrieved knowledge with price, URL, product number, or availability from a different shop item such as a reagent, accessory, kit, consumable, or service item.',
|
||||
'If a shop result has no price field, do not state a price for it.',
|
||||
'Never interpret a missing price or a zero price as free, kostenlos, gratis, or available for 0.00 EUR.',
|
||||
'Treat every SHOP PRODUCT RECORD as atomic: exact product name, product number, price, availability, URL, image, description, and metadata must stay together.',
|
||||
'When outputting a shop item, use the exact shop product name from that same SHOP PRODUCT RECORD as the heading. Never use a retrieved-knowledge device name as the heading for a different shop URL or product number.',
|
||||
'If a technical device from retrieved knowledge and a shop record are not clearly the same exact product identity, separate Fachliche Einordnung from Shop-Treffer instead of merging them.',
|
||||
]);
|
||||
return $this->getRequiredStringList('shop_results.header_lines');
|
||||
}
|
||||
|
||||
public function getLiveShopResultsOverflowNoticeTemplate(): string
|
||||
{
|
||||
return $this->getString('shop_results.overflow_notice_template', 'Only the top %d ranked shop results are shown here out of %d total results.');
|
||||
return $this->getRequiredString('shop_results.overflow_notice_template');
|
||||
}
|
||||
|
||||
public function getShopRecordHeaderTemplate(): string
|
||||
{
|
||||
return $this->getString('shop_results.record_header_template', '[%d] SHOP PRODUCT RECORD');
|
||||
return $this->getRequiredString('shop_results.record_header_template');
|
||||
}
|
||||
|
||||
public function getShopExactProductNameLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.exact_product_name_label', 'Exact shop product name');
|
||||
return $this->getRequiredString('shop_results.exact_product_name_label');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,14 +438,12 @@ final class PromptBuilderConfig
|
||||
*/
|
||||
public function getShopAtomicRecordNoteLines(): array
|
||||
{
|
||||
return $this->getStringList('shop_results.atomic_record_note_lines', [
|
||||
'Record boundary: all fields below belong only to this exact shop product record.',
|
||||
]);
|
||||
return $this->getRequiredStringList('shop_results.atomic_record_note_lines');
|
||||
}
|
||||
|
||||
public function getOutputPrioritySectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.output_priority_label', 'OUTPUT PRIORITY');
|
||||
return $this->getRequiredString('sections.output_priority_label');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,100 +726,97 @@ final class PromptBuilderConfig
|
||||
|
||||
public function getRetrievedKnowledgeSectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.retrieved_knowledge_label', 'RETRIEVED KNOWLEDGE (primary for technical matching and factual explanation)');
|
||||
return $this->getRequiredString('sections.retrieved_knowledge_label');
|
||||
}
|
||||
|
||||
public function getRetrievedKnowledgeSourceLine(): string
|
||||
{
|
||||
return $this->getString('retrieved_knowledge.source_line', 'Source: Documents');
|
||||
return $this->getRequiredString('retrieved_knowledge.source_line');
|
||||
}
|
||||
|
||||
public function getUrlContentSectionLabel(): string
|
||||
{
|
||||
return $this->getString('sections.url_content_label', 'CONTENT FROM URL (authoritative if user-provided)');
|
||||
return $this->getRequiredString('sections.url_content_label');
|
||||
}
|
||||
|
||||
public function getUrlContentSourceLine(): string
|
||||
{
|
||||
return $this->getString('url_content.source_line', 'Source: URL');
|
||||
return $this->getRequiredString('url_content.source_line');
|
||||
}
|
||||
|
||||
public function getShopProductNumberLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.product_number_label', 'Product number');
|
||||
return $this->getRequiredString('shop_results.fields.product_number_label');
|
||||
}
|
||||
|
||||
public function getShopManufacturerLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.manufacturer_label', 'Manufacturer');
|
||||
return $this->getRequiredString('shop_results.fields.manufacturer_label');
|
||||
}
|
||||
|
||||
public function getShopPriceLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.price_label', 'Price');
|
||||
return $this->getRequiredString('shop_results.fields.price_label');
|
||||
}
|
||||
|
||||
public function getShopAvailabilityLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.availability_label', 'Available');
|
||||
return $this->getRequiredString('shop_results.fields.availability_label');
|
||||
}
|
||||
|
||||
public function getShopAvailabilityYesLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.availability_yes_label', 'yes');
|
||||
return $this->getRequiredString('shop_results.fields.availability_yes_label');
|
||||
}
|
||||
|
||||
public function getShopAvailabilityNoLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.availability_no_label', 'no');
|
||||
return $this->getRequiredString('shop_results.fields.availability_no_label');
|
||||
}
|
||||
|
||||
public function getShopHighlightPrefix(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.highlight_prefix', '- ');
|
||||
return $this->getRequiredString('shop_results.fields.highlight_prefix');
|
||||
}
|
||||
|
||||
public function getShopUrlLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.url_label', 'URL');
|
||||
return $this->getRequiredString('shop_results.fields.url_label');
|
||||
}
|
||||
|
||||
public function getShopProductImageLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.product_image_label', 'Product image');
|
||||
return $this->getRequiredString('shop_results.fields.product_image_label');
|
||||
}
|
||||
|
||||
public function getShopDescriptionLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.description_label', 'Description');
|
||||
return $this->getRequiredString('shop_results.fields.description_label');
|
||||
}
|
||||
|
||||
public function getShopMetaInformationLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.meta_information_label', 'Meta information');
|
||||
return $this->getRequiredString('shop_results.fields.meta_information_label');
|
||||
}
|
||||
|
||||
public function getShopRequestedRoleLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.requested_role_label', 'Requested product role');
|
||||
return $this->getRequiredString('shop_results.fields.requested_role_label');
|
||||
}
|
||||
|
||||
public function getShopInferredRoleLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.inferred_role_label', 'Inferred shop product role');
|
||||
return $this->getRequiredString('shop_results.fields.inferred_role_label');
|
||||
}
|
||||
|
||||
public function getShopRoleCompatibilityLabel(): string
|
||||
{
|
||||
return $this->getString('shop_results.fields.role_compatibility_label', 'Role compatibility with request');
|
||||
return $this->getRequiredString('shop_results.fields.role_compatibility_label');
|
||||
}
|
||||
|
||||
public function getShopRoleIncompatibleCommercialSuppressionNote(): string
|
||||
{
|
||||
return $this->getString(
|
||||
'shop_results.fields.role_incompatible_commercial_suppression_note',
|
||||
'Commercial fields suppressed: this shop record is not a matching main-device result for the requested product role.'
|
||||
);
|
||||
return $this->getRequiredString('shop_results.fields.role_incompatible_commercial_suppression_note');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user