|
1 | 1 | package dev.langchain4j.model.bedrock; |
2 | 2 |
|
| 3 | +import static dev.langchain4j.internal.JsonSchemaElementUtils.toMap; |
3 | 4 | import static dev.langchain4j.internal.Utils.copy; |
4 | 5 | import static dev.langchain4j.internal.Utils.getOrDefault; |
5 | 6 | import static dev.langchain4j.internal.Utils.isNotNullOrEmpty; |
|
19 | 20 | import static java.util.Collections.emptyList; |
20 | 21 | import static java.util.Objects.nonNull; |
21 | 22 | import static software.amazon.awssdk.core.SdkBytes.fromByteArray; |
| 23 | +import static software.amazon.awssdk.services.bedrockruntime.model.OutputFormatType.JSON_SCHEMA; |
22 | 24 |
|
23 | 25 | import dev.langchain4j.Internal; |
24 | 26 | import dev.langchain4j.agent.tool.ToolExecutionRequest; |
|
34 | 36 | import dev.langchain4j.data.message.UserMessage; |
35 | 37 | import dev.langchain4j.exception.UnsupportedFeatureException; |
36 | 38 | import dev.langchain4j.internal.Json; |
37 | | -import dev.langchain4j.internal.JsonSchemaElementUtils; |
| 39 | +import dev.langchain4j.model.chat.Capability; |
38 | 40 | import dev.langchain4j.model.chat.listener.ChatModelListener; |
39 | 41 | import dev.langchain4j.model.chat.request.ChatRequest; |
40 | 42 | import dev.langchain4j.model.chat.request.ChatRequestParameters; |
|
43 | 45 | import dev.langchain4j.model.chat.request.ResponseFormatType; |
44 | 46 | import dev.langchain4j.model.chat.request.ToolChoice; |
45 | 47 | import dev.langchain4j.model.chat.request.json.JsonRawSchema; |
| 48 | +import dev.langchain4j.model.chat.request.json.JsonSchema; |
46 | 49 | import dev.langchain4j.model.chat.response.PartialThinking; |
47 | 50 | import dev.langchain4j.model.chat.response.StreamingChatResponseHandler; |
48 | 51 | import dev.langchain4j.model.output.FinishReason; |
49 | 52 | import java.net.URI; |
50 | 53 | import java.time.Duration; |
51 | 54 | import java.util.ArrayList; |
| 55 | +import java.util.Arrays; |
52 | 56 | import java.util.Base64; |
53 | 57 | import java.util.HashMap; |
54 | 58 | import java.util.List; |
55 | 59 | import java.util.Map; |
56 | 60 | import java.util.Objects; |
57 | 61 | import java.util.Optional; |
| 62 | +import java.util.Set; |
58 | 63 | import java.util.UUID; |
59 | 64 | import java.util.stream.Collectors; |
60 | 65 | import org.slf4j.Logger; |
@@ -121,13 +126,15 @@ abstract class AbstractBedrockChatModel { |
121 | 126 | protected final boolean sendThinking; |
122 | 127 | protected final BedrockChatRequestParameters defaultRequestParameters; |
123 | 128 | protected final List<ChatModelListener> listeners; |
| 129 | + protected final Set<Capability> supportedCapabilities; |
124 | 130 |
|
125 | 131 | protected AbstractBedrockChatModel(AbstractBuilder<?> builder) { |
126 | 132 | this.region = getOrDefault(builder.region, Region.US_EAST_1); |
127 | 133 | this.timeout = getOrDefault(builder.timeout, Duration.ofMinutes(1)); |
128 | 134 | this.returnThinking = getOrDefault(builder.returnThinking, false); |
129 | 135 | this.sendThinking = getOrDefault(builder.sendThinking, true); |
130 | 136 | this.listeners = copy(builder.listeners); |
| 137 | + this.supportedCapabilities = copy(builder.supportedCapabilities); |
131 | 138 |
|
132 | 139 | ChatRequestParameters commonParameters; |
133 | 140 | if (builder.defaultRequestParameters != null) { |
@@ -920,28 +927,27 @@ protected static OutputConfig outputConfigFrom(ResponseFormat responseFormat) { |
920 | 927 | return null; |
921 | 928 | } |
922 | 929 |
|
923 | | - if (responseFormat.jsonSchema() == null) { |
| 930 | + JsonSchema jsonSchema = responseFormat.jsonSchema(); |
| 931 | + if (jsonSchema == null) { |
924 | 932 | throw new UnsupportedFeatureException("JSON response format is not supported without a schema"); |
925 | 933 | } |
926 | 934 |
|
927 | | - // JSON with schema - use structured output |
928 | | - String schemaJson; |
929 | | - if (responseFormat.jsonSchema().rootElement() instanceof JsonRawSchema rawSchema) { |
930 | | - // For raw JSON schema, use the raw string directly |
931 | | - schemaJson = rawSchema.schema(); |
| 935 | + String jsonSchemaString; |
| 936 | + if (jsonSchema.rootElement() instanceof JsonRawSchema rawSchema) { |
| 937 | + jsonSchemaString = rawSchema.schema(); |
932 | 938 | } else { |
933 | | - // For structured schema, convert to Map then to JSON string |
934 | 939 | Map<String, Object> jsonSchemaMap = |
935 | | - JsonSchemaElementUtils.toMap(responseFormat.jsonSchema().rootElement()); |
936 | | - schemaJson = Json.toJson(jsonSchemaMap); |
| 940 | + toMap(jsonSchema.rootElement(), true, true, "string"); |
| 941 | + jsonSchemaString = Json.toJson(jsonSchemaMap); |
937 | 942 | } |
938 | 943 |
|
939 | 944 | return OutputConfig.builder() |
940 | 945 | .textFormat(OutputFormat.builder() |
941 | | - .type(OutputFormatType.JSON_SCHEMA) |
| 946 | + .type(JSON_SCHEMA) |
942 | 947 | .structure(OutputFormatStructure.builder() |
943 | 948 | .jsonSchema(JsonSchemaDefinition.builder() |
944 | | - .schema(schemaJson) |
| 949 | + .schema(jsonSchemaString) |
| 950 | + .name(jsonSchema.name()) |
945 | 951 | .build()) |
946 | 952 | .build()) |
947 | 953 | .build()) |
@@ -975,6 +981,7 @@ public abstract static class AbstractBuilder<T extends AbstractBuilder<T>> { |
975 | 981 | protected Boolean logResponses; |
976 | 982 | protected Logger logger; |
977 | 983 | protected List<ChatModelListener> listeners; |
| 984 | + protected Set<Capability> supportedCapabilities; |
978 | 985 |
|
979 | 986 | @SuppressWarnings("unchecked") |
980 | 987 | public T self() { |
@@ -1080,5 +1087,15 @@ public T listeners(List<ChatModelListener> listeners) { |
1080 | 1087 | public T listeners(ChatModelListener... listeners) { |
1081 | 1088 | return listeners(asList(listeners)); |
1082 | 1089 | } |
| 1090 | + |
| 1091 | + public T supportedCapabilities(Set<Capability> supportedCapabilities) { |
| 1092 | + this.supportedCapabilities = supportedCapabilities; |
| 1093 | + return self(); |
| 1094 | + } |
| 1095 | + |
| 1096 | + public T supportedCapabilities(Capability... supportedCapabilities) { |
| 1097 | + this.supportedCapabilities = Arrays.stream(supportedCapabilities).collect(Collectors.toSet()); |
| 1098 | + return self(); |
| 1099 | + } |
1083 | 1100 | } |
1084 | 1101 | } |
0 commit comments