diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws-bedrock.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws-bedrock.json index 8356314345146..0281e4dfd925c 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws-bedrock.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws-bedrock.json @@ -71,12 +71,13 @@ "CamelAwsBedrockConverseUsage": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "TokenUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The usage metrics from Converse API response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#CONVERSE_USAGE" }, "CamelAwsBedrockConverseOutputMessage": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Message", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The output message from Converse API response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#CONVERSE_OUTPUT_MESSAGE" }, "CamelAwsBedrockGuardrailConfig": { "index": 15, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailConfiguration", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail configuration to apply to the request", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONFIG" }, - "CamelAwsBedrockGuardrailContent": { "index": 16, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content blocks for ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONTENT" }, - "CamelAwsBedrockGuardrailSource": { "index": 17, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The source type for ApplyGuardrail operation (INPUT or OUTPUT)", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_SOURCE" }, - "CamelAwsBedrockGuardrailOutput": { "index": 18, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailAssessment", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessment output from the response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_OUTPUT" }, - "CamelAwsBedrockGuardrailTrace": { "index": 19, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailTrace", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The trace information from guardrail evaluation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_TRACE" }, - "CamelAwsBedrockGuardrailAssessments": { "index": 20, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessments from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_ASSESSMENTS" }, - "CamelAwsBedrockGuardrailUsage": { "index": 21, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail usage metrics from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_USAGE" } + "CamelAwsBedrockGuardrailIdentifier": { "index": 16, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail identifier to use for the ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_IDENTIFIER" }, + "CamelAwsBedrockGuardrailContent": { "index": 17, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content blocks for ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONTENT" }, + "CamelAwsBedrockGuardrailSource": { "index": 18, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The source type for ApplyGuardrail operation (INPUT or OUTPUT)", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_SOURCE" }, + "CamelAwsBedrockGuardrailOutput": { "index": 19, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailAssessment", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessment output from the response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_OUTPUT" }, + "CamelAwsBedrockGuardrailTrace": { "index": 20, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailTrace", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The trace information from guardrail evaluation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_TRACE" }, + "CamelAwsBedrockGuardrailAssessments": { "index": 21, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessments from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_ASSESSMENTS" }, + "CamelAwsBedrockGuardrailUsage": { "index": 22, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail usage metrics from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_USAGE" } }, "properties": { "label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConfiguration", "configurationField": "configuration", "description": "Logical name" }, diff --git a/components/camel-aws/camel-aws-bedrock/pom.xml b/components/camel-aws/camel-aws-bedrock/pom.xml index cfc8d86bc30bf..0b35ee2d25831 100644 --- a/components/camel-aws/camel-aws-bedrock/pom.xml +++ b/components/camel-aws/camel-aws-bedrock/pom.xml @@ -103,5 +103,11 @@ test-jar test + + org.mockito + mockito-junit-jupiter + ${mockito-version} + test + diff --git a/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/runtime/aws-bedrock.json b/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/runtime/aws-bedrock.json index 8356314345146..0281e4dfd925c 100644 --- a/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/runtime/aws-bedrock.json +++ b/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/runtime/aws-bedrock.json @@ -71,12 +71,13 @@ "CamelAwsBedrockConverseUsage": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "TokenUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The usage metrics from Converse API response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#CONVERSE_USAGE" }, "CamelAwsBedrockConverseOutputMessage": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Message", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The output message from Converse API response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#CONVERSE_OUTPUT_MESSAGE" }, "CamelAwsBedrockGuardrailConfig": { "index": 15, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailConfiguration", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail configuration to apply to the request", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONFIG" }, - "CamelAwsBedrockGuardrailContent": { "index": 16, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content blocks for ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONTENT" }, - "CamelAwsBedrockGuardrailSource": { "index": 17, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The source type for ApplyGuardrail operation (INPUT or OUTPUT)", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_SOURCE" }, - "CamelAwsBedrockGuardrailOutput": { "index": 18, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailAssessment", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessment output from the response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_OUTPUT" }, - "CamelAwsBedrockGuardrailTrace": { "index": 19, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailTrace", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The trace information from guardrail evaluation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_TRACE" }, - "CamelAwsBedrockGuardrailAssessments": { "index": 20, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessments from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_ASSESSMENTS" }, - "CamelAwsBedrockGuardrailUsage": { "index": 21, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail usage metrics from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_USAGE" } + "CamelAwsBedrockGuardrailIdentifier": { "index": 16, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail identifier to use for the ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_IDENTIFIER" }, + "CamelAwsBedrockGuardrailContent": { "index": 17, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content blocks for ApplyGuardrail operation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_CONTENT" }, + "CamelAwsBedrockGuardrailSource": { "index": 18, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The source type for ApplyGuardrail operation (INPUT or OUTPUT)", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_SOURCE" }, + "CamelAwsBedrockGuardrailOutput": { "index": 19, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailAssessment", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessment output from the response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_OUTPUT" }, + "CamelAwsBedrockGuardrailTrace": { "index": 20, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailTrace", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The trace information from guardrail evaluation", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_TRACE" }, + "CamelAwsBedrockGuardrailAssessments": { "index": 21, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail assessments from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_ASSESSMENTS" }, + "CamelAwsBedrockGuardrailUsage": { "index": 22, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "GuardrailUsage", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The guardrail usage metrics from ApplyGuardrail response", "constantName": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConstants#GUARDRAIL_USAGE" } }, "properties": { "label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.bedrock.runtime.BedrockConfiguration", "configurationField": "configuration", "description": "Logical name" }, diff --git a/components/camel-aws/camel-aws-bedrock/src/main/docs/aws-bedrock-component.adoc b/components/camel-aws/camel-aws-bedrock/src/main/docs/aws-bedrock-component.adoc index 598590a6e8f8a..591da05643eec 100644 --- a/components/camel-aws/camel-aws-bedrock/src/main/docs/aws-bedrock-component.adoc +++ b/components/camel-aws/camel-aws-bedrock/src/main/docs/aws-bedrock-component.adoc @@ -803,6 +803,7 @@ The Camel AWS Bedrock component provides comprehensive support for guardrails th *Message-level Configuration* (per-message override via headers): - `CamelAwsBedrockGuardrailConfig`: GuardrailConfiguration object for converse operations +- `CamelAwsBedrockGuardrailIdentifier`: Guardrail identifier String for the applyGuardrail operation (overrides the endpoint `guardrailIdentifier`) - `CamelAwsBedrockGuardrailContent`: Content blocks for applyGuardrail operation - `CamelAwsBedrockGuardrailSource`: Source type - "INPUT" or "OUTPUT" for applyGuardrail diff --git a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockConstants.java b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockConstants.java index 9feeb736cc3de..0ab3692e57750 100644 --- a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockConstants.java +++ b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockConstants.java @@ -55,6 +55,8 @@ public interface BedrockConstants { String CONVERSE_OUTPUT_MESSAGE = "CamelAwsBedrockConverseOutputMessage"; @Metadata(description = "The guardrail configuration to apply to the request", javaType = "GuardrailConfiguration") String GUARDRAIL_CONFIG = "CamelAwsBedrockGuardrailConfig"; + @Metadata(description = "The guardrail identifier to use for the ApplyGuardrail operation", javaType = "String") + String GUARDRAIL_IDENTIFIER = "CamelAwsBedrockGuardrailIdentifier"; @Metadata(description = "The content blocks for ApplyGuardrail operation", javaType = "List") String GUARDRAIL_CONTENT = "CamelAwsBedrockGuardrailContent"; @Metadata(description = "The source type for ApplyGuardrail operation (INPUT or OUTPUT)", javaType = "String") diff --git a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java index cac050a892a07..e3959f387e8ea 100644 --- a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java +++ b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java @@ -806,7 +806,8 @@ private void applyGuardrail(BedrockRuntimeClient bedrockRuntimeClient, Exchange = software.amazon.awssdk.services.bedrockruntime.model.ApplyGuardrailRequest.builder(); // Guardrail identifier from header or configuration - String guardrailIdentifier = exchange.getMessage().getHeader(BedrockConstants.GUARDRAIL_CONFIG, String.class); + String guardrailIdentifier + = exchange.getMessage().getHeader(BedrockConstants.GUARDRAIL_IDENTIFIER, String.class); if (ObjectHelper.isEmpty(guardrailIdentifier)) { guardrailIdentifier = getConfiguration().getGuardrailIdentifier(); } diff --git a/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockApplyGuardrailTest.java b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockApplyGuardrailTest.java new file mode 100644 index 0000000000000..c0e0a05418cc3 --- /dev/null +++ b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockApplyGuardrailTest.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.aws2.bedrock.runtime; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.support.SimpleRegistry; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient; +import software.amazon.awssdk.services.bedrockruntime.model.ApplyGuardrailRequest; +import software.amazon.awssdk.services.bedrockruntime.model.ApplyGuardrailResponse; +import software.amazon.awssdk.services.bedrockruntime.model.GuardrailAction; +import software.amazon.awssdk.services.bedrockruntime.model.GuardrailConfiguration; +import software.amazon.awssdk.services.bedrockruntime.model.GuardrailContentBlock; +import software.amazon.awssdk.services.bedrockruntime.model.GuardrailTextBlock; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; + +/** + * Unit tests for the {@code applyGuardrail} producer operation. Uses a mocked {@link BedrockRuntimeClient} so the test + * exercises only the producer's request-building logic — no AWS credentials or network access required. + */ +@ExtendWith(MockitoExtension.class) +public class BedrockApplyGuardrailTest { + + @Mock + private BedrockRuntimeClient client; + + private CamelContext camelContext; + private ProducerTemplate template; + private AtomicReference capturedRequest; + + @BeforeEach + public void setup() throws Exception { + capturedRequest = new AtomicReference<>(); + lenient().doAnswer(invocation -> { + capturedRequest.set(invocation.getArgument(0, ApplyGuardrailRequest.class)); + return ApplyGuardrailResponse.builder().action(GuardrailAction.NONE).build(); + }).when(client).applyGuardrail(any(ApplyGuardrailRequest.class)); + + SimpleRegistry registry = new SimpleRegistry(); + registry.bind("bedrockClient", client); + camelContext = new DefaultCamelContext(registry); + camelContext.addRoutes(new RouteBuilder() { + @Override + public void configure() { + from("direct:apply-guardrail-config") + .to("aws-bedrock://label" + + "?bedrockRuntimeClient=#bedrockClient" + + "&operation=applyGuardrail" + + "&guardrailIdentifier=endpoint-guardrail-id" + + "&guardrailVersion=1" + + "®ion=us-east-1" + + "&accessKey=unused" + + "&secretKey=unused"); + + from("direct:apply-guardrail-no-config") + .to("aws-bedrock://label2" + + "?bedrockRuntimeClient=#bedrockClient" + + "&operation=applyGuardrail" + + "®ion=us-east-1" + + "&accessKey=unused" + + "&secretKey=unused"); + } + }); + camelContext.start(); + template = camelContext.createProducerTemplate(); + } + + @AfterEach + public void teardown() { + if (template != null) { + template.stop(); + } + if (camelContext != null) { + camelContext.stop(); + } + } + + @Test + public void applyGuardrailUsesEndpointGuardrailIdentifierWhenNoHeader() { + template.send("direct:apply-guardrail-config", + exchange -> exchange.getMessage().setHeader(BedrockConstants.GUARDRAIL_CONTENT, sampleContent())); + + ApplyGuardrailRequest request = capturedRequest.get(); + assertNotNull(request, "Producer must have invoked the bedrock client"); + assertEquals("endpoint-guardrail-id", request.guardrailIdentifier(), + "Identifier should fall back to the endpoint configuration when no header is set"); + } + + @Test + public void applyGuardrailUsesGuardrailIdentifierHeaderWhenSet() { + template.send("direct:apply-guardrail-config", exchange -> { + exchange.getMessage().setHeader(BedrockConstants.GUARDRAIL_IDENTIFIER, "header-guardrail-id"); + exchange.getMessage().setHeader(BedrockConstants.GUARDRAIL_CONTENT, sampleContent()); + }); + + ApplyGuardrailRequest request = capturedRequest.get(); + assertNotNull(request); + assertEquals("header-guardrail-id", request.guardrailIdentifier(), + "Identifier should be read from the CamelAwsBedrockGuardrailIdentifier header"); + } + + @Test + public void applyGuardrailDoesNotReadIdentifierFromGuardrailConfigHeader() { + // GUARDRAIL_CONFIG carries a GuardrailConfiguration (used by converse), not a String identifier. + // Setting it must not corrupt the applyGuardrail request — the endpoint identifier must still be used. + template.send("direct:apply-guardrail-config", exchange -> { + GuardrailConfiguration converseConfig = GuardrailConfiguration.builder() + .guardrailIdentifier("converse-guardrail-id") + .guardrailVersion("DRAFT") + .build(); + exchange.getMessage().setHeader(BedrockConstants.GUARDRAIL_CONFIG, converseConfig); + exchange.getMessage().setHeader(BedrockConstants.GUARDRAIL_CONTENT, sampleContent()); + }); + + ApplyGuardrailRequest request = capturedRequest.get(); + assertNotNull(request); + assertEquals("endpoint-guardrail-id", request.guardrailIdentifier(), + "applyGuardrail must not consume the GuardrailConfiguration from CamelAwsBedrockGuardrailConfig"); + } + + @Test + public void applyGuardrailFailsWhenGuardrailIdentifierIsMissing() { + Exchange exchange = template.send("direct:apply-guardrail-no-config", + ex -> ex.getMessage().setHeader(BedrockConstants.GUARDRAIL_CONTENT, sampleContent())); + Throwable cause = exchange.getException(); + assertNotNull(cause, "Producer should fail when no guardrailIdentifier is provided"); + assertInstanceOf(IllegalArgumentException.class, cause); + assertTrue(cause.getMessage().contains("guardrailIdentifier"), + "Error message should mention guardrailIdentifier — was: " + cause.getMessage()); + } + + private static List sampleContent() { + List content = new ArrayList<>(); + content.add(GuardrailContentBlock.builder() + .text(GuardrailTextBlock.builder().text("test").build()) + .build()); + return content; + } +} diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index e891799b75abc..eb2683ca3721a 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -13,6 +13,16 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details. == Upgrading from 4.18.2 to 4.18.3 +=== camel-aws-bedrock + +The `applyGuardrail` producer operation now reads the guardrail identifier from a new dedicated header +`CamelAwsBedrockGuardrailIdentifier` (constant `BedrockConstants.GUARDRAIL_IDENTIFIER`, typed `String`) +instead of `CamelAwsBedrockGuardrailConfig`. The `CamelAwsBedrockGuardrailConfig` header is typed +`GuardrailConfiguration` and is reserved for the `converse` and `converseStream` operations; the +previous code path silently produced `null` whenever a route mixed `converse` and `applyGuardrail` +calls. If you were not setting the guardrail identifier via header, the endpoint-level +`guardrailIdentifier` option continues to work without changes. + === camel-hazelcast Hazelcast instances created and managed by Camel (when no user-supplied diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BedrockEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BedrockEndpointBuilderFactory.java index d7f8ed869fa4b..a71c596ec0dbf 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BedrockEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BedrockEndpointBuilderFactory.java @@ -944,6 +944,18 @@ public String awsBedrockConverseOutputMessage() { public String awsBedrockGuardrailConfig() { return "CamelAwsBedrockGuardrailConfig"; } + /** + * The guardrail identifier to use for the ApplyGuardrail operation. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code AwsBedrockGuardrailIdentifier}. + */ + public String awsBedrockGuardrailIdentifier() { + return "CamelAwsBedrockGuardrailIdentifier"; + } /** * The content blocks for ApplyGuardrail operation. *