001/* 002 * Copyright (c) 2026, Oracle and/or its affiliates. 003 * 004 * Licensed under the Universal Permissive License Version 1.0 as shown at 005 * https://oss.oracle.com/licenses/upl/ 006 */ 007package com.oracle.database.selectai.model; 008 009import com.fasterxml.jackson.annotation.JsonInclude; 010import com.fasterxml.jackson.annotation.JsonIgnore; 011import com.fasterxml.jackson.databind.ObjectMapper; 012import com.fasterxml.jackson.databind.PropertyNamingStrategies; 013 014import java.util.ArrayList; 015import java.util.Collections; 016import java.util.HashMap; 017import java.util.List; 018import java.util.Locale; 019import java.util.Map; 020 021/** 022 * Attribute payload for {@code DBMS_CLOUD_AI.CREATE_PROFILE}, 023 * {@code SET_ATTRIBUTE}, and {@code SET_ATTRIBUTES}. 024 * <p> 025 * Profile attributes describe the provider, AI model, credential, object 026 * selection, prompt behavior, conversation behavior, and RAG/vector-index 027 * settings that Select AI uses when answering prompts. Most attributes map to 028 * database-side Select AI profile settings; callers can build the payload once 029 * for profile creation or reuse it for bulk updates. 030 * <p> 031 * For complete runnable sample sources that build {@code ProfileAttributes}, 032 * see 033 * <a href="{@docRoot}/src-html/com/oracle/database/selectai/samples/profile/CreateProfileSample.html"> 034 * CreateProfileSample source</a> and 035 * <a href="{@docRoot}/src-html/com/oracle/database/selectai/samples/profile/SetProfileAttributesSample.html"> 036 * SetProfileAttributesSample source</a>. 037 * 038 * <p>Commonly used profile attributes include:</p> 039 * 040 * <table> 041 * <caption>Common Select AI profile attributes</caption> 042 * <tr> 043 * <th>Attribute</th> 044 * <th>Description</th> 045 * </tr> 046 * <tr> 047 * <td>{@code provider}</td> 048 * <td>AI provider used by the profile.</td> 049 * </tr> 050 * <tr> 051 * <td>{@code credential_name}</td> 052 * <td>Credential used to access the AI provider, where required.</td> 053 * </tr> 054 * <tr> 055 * <td>{@code model}</td> 056 * <td>AI model used by the profile.</td> 057 * </tr> 058 * <tr> 059 * <td>{@code object_list}</td> 060 * <td>Database objects available for NL2SQL processing.</td> 061 * </tr> 062 * <tr> 063 * <td>{@code object_list_mode}</td> 064 * <td>Controls how database objects are selected for NL2SQL processing.</td> 065 * </tr> 066 * <tr> 067 * <td>{@code temperature}</td> 068 * <td>Controls randomness in model-generated responses.</td> 069 * </tr> 070 * <tr> 071 * <td>{@code max_tokens}</td> 072 * <td>Specifies the maximum number of tokens to generate.</td> 073 * </tr> 074 * <tr> 075 * <td>{@code vector_index_name}</td> 076 * <td>Specifies the vector index associated with the profile.</td> 077 * </tr> 078 * </table> 079 * 080 * <p> 081 * The SDK performs basic, deterministic validation of profile attributes where 082 * the constraint can be validated independently of the configured provider or 083 * database version. This includes validation of supported SDK-defined values, 084 * numeric constraints, and basic input structure. Invalid values detected by 085 * the SDK result in an {@link IllegalArgumentException}. 086 * 087 * <p> 088 * Provider-specific, model-specific, database-version-specific, and other 089 * database-side semantic validation is delegated to {@code DBMS_CLOUD_AI} and 090 * Oracle Database. Therefore, an attribute value that passes SDK validation 091 * may still be rejected by the database based on the selected provider, model, 092 * database version, or other database-side requirements. 093 * 094 * <p> 095 * Supported profile attributes, valid values, defaults, requirements, and 096 * provider-specific behavior are defined by Oracle Database and may vary by 097 * database version and provider. See the {@code DBMS_CLOUD_AI} Profile 098 * Attributes documentation for the complete and current list. 099 * 100 * @see <a href="https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/dbms-cloud-ai-package.html#GUID-12D91681-B51C-48E0-93FD-9ABC67B0F375"> 101 * DBMS_CLOUD_AI Profile Attributes</a> 102 * @see <a href="https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/select-ai-manage-profiles.html"> 103 * Manage AI profiles</a> 104 */ 105public final class ProfileAttributes { 106 /** Include table/column annotations (26ai) in augmented metadata. Default: false. */ 107 private final Boolean annotations; 108 /** Additional prompt instructions supplied to Select AI. */ 109 private final String additionalInstructions; 110 /** Azure OpenAI deployment name for chat/completion model. */ 111 private final String azureDeploymentName; 112 /** Azure OpenAI deployment name for embedding model. */ 113 private final String azureEmbeddingDeploymentName; 114 /** Azure OpenAI resource name. */ 115 private final String azureResourceName; 116 /** Whether SQL value matching should be case-sensitive. Default: false. */ 117 private final Boolean caseSensitiveValues; 118 /** Include table and column comments in metadata sent to LLM. Default: false. */ 119 private final Boolean comments; 120 /** Include referential constraints in metadata. Default: false. */ 121 private final Boolean constraints; 122 /** Enable conversation history for profile. Default: false. */ 123 private final Boolean conversation; 124 /** Number of past turns retained when conversation is enabled. */ 125 private final Integer conversationLength; 126 /** Credential name used to call provider APIs, where required. */ 127 private final String credentialName; 128 /** Embedding model name. */ 129 private final String embeddingModel; 130 /** Enables custom source URL metadata for RAG citations. Default: false. */ 131 private final Boolean enableCustomSourceUri; 132 /** Restrict SQL generation to objects listed in objectList. Default: false. */ 133 private final Boolean enforceObjectList; 134 /** Maximum tokens generated per response. */ 135 private final Integer maxTokens; 136 /** Provider model identifier. */ 137 private final String model; 138 /** JSON array of objects eligible for NL2SQL (owner mandatory, name optional). */ 139 private final String objectList; 140 /** Metadata selection mode: all or automated. */ 141 private final String objectListMode; 142 /** OCI API format for dedicated endpoint/model OCID (COHERE|GENERIC). */ 143 private final String ociApiformat; 144 /** OCI compartment OCID. */ 145 private final String ociCompartmentId; 146 /** OCI dedicated endpoint OCID. */ 147 private final String ociEndpointId; 148 /** OCI runtime type (deprecated in favor of oci_apiformat). */ 149 private final String ociRuntimetype; 150 /** AI provider name (mandatory). */ 151 private final String provider; 152 /** Provider endpoint host/path for OpenAI-compatible providers. */ 153 private final String providerEndpoint; 154 /** Provider region. */ 155 private final String region; 156 /** Role prompt supplied to Select AI. */ 157 private final String role; 158 /** Optional deterministic sampling seed (signed 64-bit integer). */ 159 private final Long seed; 160 /** Stop sequences for generation. */ 161 private final List<String> stopTokens; 162 /** Non-negative sampling temperature. */ 163 private final Double temperature; 164 /** Vector index name (Oracle SQL identifier, up to 125 chars). */ 165 private final String vectorIndexName; 166 /** Source language for translation. */ 167 private final String sourceLanguage; 168 /** Target language for translation. */ 169 private final String targetLanguage; 170 /** Unmodeled attributes preserved for metadata round-tripping. */ 171 private final Map<String, String> customAttributes; 172 173 private ProfileAttributes(Builder builder) { 174 this.annotations = builder.annotations; 175 this.additionalInstructions = builder.additionalInstructions; 176 this.azureDeploymentName = builder.azureDeploymentName; 177 this.azureEmbeddingDeploymentName = builder.azureEmbeddingDeploymentName; 178 this.azureResourceName = builder.azureResourceName; 179 this.caseSensitiveValues = builder.caseSensitiveValues; 180 this.comments = builder.comments; 181 this.constraints = builder.constraints; 182 this.conversation = builder.conversation; 183 this.conversationLength = builder.conversationLength; 184 this.credentialName = builder.credentialName; 185 this.embeddingModel = builder.embeddingModel; 186 this.enableCustomSourceUri = builder.enableCustomSourceUri; 187 this.enforceObjectList = builder.enforceObjectList; 188 this.maxTokens = builder.maxTokens; 189 this.model = builder.model; 190 this.objectList = builder.objectList; 191 this.objectListMode = builder.objectListMode; 192 this.ociApiformat = builder.ociApiformat; 193 this.ociCompartmentId = builder.ociCompartmentId; 194 this.ociEndpointId = builder.ociEndpointId; 195 this.ociRuntimetype = builder.ociRuntimetype; 196 this.provider = builder.provider; 197 this.providerEndpoint = builder.providerEndpoint; 198 this.region = builder.region; 199 this.role = builder.role; 200 this.seed = builder.seed; 201 this.stopTokens = builder.stopTokens == null ? null : List.copyOf(builder.stopTokens); 202 this.temperature = builder.temperature; 203 this.vectorIndexName = builder.vectorIndexName; 204 this.sourceLanguage = builder.sourceLanguage; 205 this.targetLanguage = builder.targetLanguage; 206 this.customAttributes = Collections.unmodifiableMap(new HashMap<>(builder.customAttributes)); 207 } 208 209 /** 210 * Creates a builder for profile attributes. 211 * 212 * @return new builder for constructing ProfileAttributes 213 */ 214 public static Builder builder() { 215 return new Builder(); 216 } 217 218 /** 219 * Returns whether table/column annotations are included in metadata. 220 * 221 * @return annotations flag value, or {@code null} when unset 222 */ 223 public Boolean getAnnotations() { 224 return annotations; 225 } 226 227 /** 228 * Returns additional instructions included in Select AI prompts. 229 * 230 * @return additional instructions, or {@code null} when unset 231 */ 232 public String getAdditionalInstructions() { 233 return additionalInstructions; 234 } 235 236 /** 237 * Returns the Azure OpenAI deployment name. 238 * 239 * @return Azure deployment name, or {@code null} when unset 240 */ 241 public String getAzureDeploymentName() { 242 return azureDeploymentName; 243 } 244 245 /** 246 * Returns the Azure OpenAI embedding deployment name. 247 * 248 * @return Azure embedding deployment name, or {@code null} when unset 249 */ 250 public String getAzureEmbeddingDeploymentName() { 251 return azureEmbeddingDeploymentName; 252 } 253 254 /** 255 * Returns the Azure OpenAI resource name. 256 * 257 * @return Azure resource name, or {@code null} when unset 258 */ 259 public String getAzureResourceName() { 260 return azureResourceName; 261 } 262 263 /** 264 * Returns whether generated SQL value matching is case-sensitive. 265 * 266 * @return case-sensitive-values flag, or {@code null} when unset 267 */ 268 public Boolean getCaseSensitiveValues() { 269 return caseSensitiveValues; 270 } 271 272 /** 273 * Returns whether table and column comments are included in prompt metadata. 274 * 275 * @return comments flag, or {@code null} when unset 276 */ 277 public Boolean getComments() { 278 return comments; 279 } 280 281 /** 282 * Returns whether referential constraints are included in prompt metadata. 283 * 284 * @return constraints flag, or {@code null} when unset 285 */ 286 public Boolean getConstraints() { 287 return constraints; 288 } 289 290 /** 291 * Returns whether conversation history is enabled for the profile. 292 * 293 * @return conversation flag, or {@code null} when unset 294 */ 295 public Boolean getConversation() { 296 return conversation; 297 } 298 299 /** 300 * Returns how many conversation turns are retained for context. 301 * 302 * @return configured conversation length, or {@code null} when unset 303 */ 304 public Integer getConversationLength() { 305 return conversationLength; 306 } 307 308 /** 309 * Returns the credential name used for provider API calls. 310 * 311 * @return credential name, or {@code null} when unset 312 */ 313 public String getCredentialName() { 314 return credentialName; 315 } 316 317 /** 318 * Returns the embedding model name. 319 * 320 * @return embedding model name, or {@code null} when unset 321 */ 322 public String getEmbeddingModel() { 323 return embeddingModel; 324 } 325 326 /** 327 * Returns whether custom source URI metadata is enabled. 328 * 329 * @return custom-source-URI flag, or {@code null} when unset 330 */ 331 public Boolean getEnableCustomSourceUri() { 332 return enableCustomSourceUri; 333 } 334 335 /** 336 * Returns whether SQL generation is restricted to {@code object_list}. 337 * 338 * @return enforce-object-list flag, or {@code null} when unset 339 */ 340 public Boolean getEnforceObjectList() { 341 return enforceObjectList; 342 } 343 344 /** 345 * Returns the maximum generated output tokens. 346 * 347 * @return maximum tokens value, or {@code null} when unset 348 */ 349 public Integer getMaxTokens() { 350 return maxTokens; 351 } 352 353 /** 354 * Returns the provider model identifier. 355 * 356 * @return provider model identifier, or {@code null} when unset 357 */ 358 public String getModel() { 359 return model; 360 } 361 362 /** 363 * Returns the JSON object list supplied to Select AI. 364 * 365 * @return object-list JSON string, or {@code null} when unset 366 */ 367 public String getObjectList() { 368 return objectList; 369 } 370 371 /** 372 * Returns how Select AI chooses objects for metadata. 373 * 374 * @return object-list mode value, or {@code null} when unset 375 */ 376 public String getObjectListMode() { 377 return objectListMode; 378 } 379 380 /** 381 * Returns the OCI Generative AI API format. 382 * 383 * @return OCI API format value, or {@code null} when unset 384 */ 385 public String getOciApiformat() { 386 return ociApiformat; 387 } 388 389 /** 390 * Returns the OCI compartment OCID. 391 * 392 * @return OCI compartment ID, or {@code null} when unset 393 */ 394 public String getOciCompartmentId() { 395 return ociCompartmentId; 396 } 397 398 /** 399 * Returns the OCI dedicated endpoint OCID. 400 * 401 * @return OCI endpoint ID, or {@code null} when unset 402 */ 403 public String getOciEndpointId() { 404 return ociEndpointId; 405 } 406 407 /** 408 * Returns the OCI runtime type attribute. 409 * 410 * @return OCI runtime type value, or {@code null} when unset 411 */ 412 public String getOciRuntimetype() { 413 return ociRuntimetype; 414 } 415 416 /** 417 * Returns the AI provider name. 418 * 419 * @return provider name, or {@code null} when unset 420 */ 421 public String getProvider() { 422 return provider; 423 } 424 425 /** 426 * Returns the provider endpoint host/path. 427 * 428 * @return provider endpoint value, or {@code null} when unset 429 */ 430 public String getProviderEndpoint() { 431 return providerEndpoint; 432 } 433 434 /** 435 * Returns the provider region. 436 * 437 * @return configured region value, or {@code null} when unset 438 */ 439 public String getRegion() { 440 return region; 441 } 442 443 /** 444 * Returns the role prompt used by Select AI. 445 * 446 * @return role prompt, or {@code null} when unset 447 */ 448 public String getRole() { 449 return role; 450 } 451 452 /** 453 * Returns the deterministic sampling seed. 454 * 455 * @return deterministic sampling seed, or {@code null} when unset 456 */ 457 public Long getSeed() { 458 return seed; 459 } 460 461 /** 462 * Returns stop tokens used to terminate generation. 463 * 464 * @return configured stop-token list, or {@code null} when unset 465 */ 466 public List<String> getStopTokens() { 467 return stopTokens; 468 } 469 470 /** 471 * Returns the provider sampling temperature. 472 * 473 * @return sampling temperature, or {@code null} when unset 474 */ 475 public Double getTemperature() { 476 return temperature; 477 } 478 479 /** 480 * Returns the vector index name associated with this profile. 481 * 482 * @return vector index name, or {@code null} when unset 483 */ 484 public String getVectorIndexName() { 485 return vectorIndexName; 486 } 487 488 /** 489 * Returns the source language for translation requests. 490 * 491 * @return source language for translation, or {@code null} when unset 492 */ 493 public String getSourceLanguage() { 494 return sourceLanguage; 495 } 496 497 /** 498 * Returns the target language for translation requests. 499 * 500 * @return target language for translation, or {@code null} when unset 501 */ 502 public String getTargetLanguage() { 503 return targetLanguage; 504 } 505 506 /** 507 * Returns unmodeled database attributes preserved for forward-compatible 508 * metadata round-tripping. 509 * <p> 510 * These values are emitted by {@link #toAttributeMap()} but excluded from 511 * {@link #toJson()} to avoid sending a nested {@code custom_attributes} 512 * object to {@code DBMS_CLOUD_AI}. 513 * 514 * @return immutable map of custom attribute names and values 515 */ 516 @JsonIgnore 517 public Map<String, String> getCustomAttributes() { 518 return customAttributes; 519 } 520 521 /** 522 * Converts non-null attributes to DBMS_CLOUD_AI attribute names and string values. 523 * 524 * @return map containing non-null profile attributes 525 */ 526 public Map<String, String> toAttributeMap() { 527 Map<String, String> map = new HashMap<>(); 528 putIfNotNull(map, "annotations", annotations); 529 putIfNotNull(map, "additional_instructions", additionalInstructions); 530 putIfNotNull(map, "azure_deployment_name", azureDeploymentName); 531 putIfNotNull(map, "azure_embedding_deployment_name", azureEmbeddingDeploymentName); 532 putIfNotNull(map, "azure_resource_name", azureResourceName); 533 putIfNotNull(map, "case_sensitive_values", caseSensitiveValues); 534 putIfNotNull(map, "comments", comments); 535 putIfNotNull(map, "constraints", constraints); 536 putIfNotNull(map, "conversation", conversation); 537 putIfNotNull(map, "conversation_length", conversationLength); 538 putIfNotNull(map, "credential_name", credentialName); 539 putIfNotNull(map, "embedding_model", embeddingModel); 540 putIfNotNull(map, "enable_custom_source_uri", enableCustomSourceUri); 541 putIfNotNull(map, "enforce_object_list", enforceObjectList); 542 putIfNotNull(map, "max_tokens", maxTokens); 543 putIfNotNull(map, "model", model); 544 putIfNotNull(map, "object_list", objectList); 545 putIfNotNull(map, "object_list_mode", objectListMode); 546 putIfNotNull(map, "oci_apiformat", ociApiformat); 547 putIfNotNull(map, "oci_compartment_id", ociCompartmentId); 548 putIfNotNull(map, "oci_endpoint_id", ociEndpointId); 549 putIfNotNull(map, "oci_runtimetype", ociRuntimetype); 550 putIfNotNull(map, "provider", provider); 551 putIfNotNull(map, "provider_endpoint", providerEndpoint); 552 putIfNotNull(map, "region", region); 553 putIfNotNull(map, "role", role); 554 putIfNotNull(map, "seed", seed); 555 putStopTokensIfNotNull(map, stopTokens); 556 putIfNotNull(map, "temperature", temperature); 557 putIfNotNull(map, "vector_index_name", vectorIndexName); 558 putIfNotNull(map, "source_language", sourceLanguage); 559 putIfNotNull(map, "target_language", targetLanguage); 560 map.putAll(customAttributes); 561 return map; 562 } 563 564 /** 565 * Builds a {@link ProfileAttributes} instance from an attribute name/value map. 566 * <p> 567 * Recognized keys are converted to strongly-typed builder fields; unknown 568 * keys are accepted so metadata reads do not fail when the database exposes a 569 * newer attribute than this SDK version supports directly. 570 * 571 * @param attributes attribute map (typically DB-sourced key/value pairs) 572 * @return populated {@link ProfileAttributes} instance 573 */ 574 public static ProfileAttributes fromAttributeMap(Map<String, String> attributes) { 575 Builder builder = ProfileAttributes.builder(); 576 if (attributes == null || attributes.isEmpty()) { 577 return builder.build(); 578 } 579 580 attributes.forEach((k, v) -> { 581 if (k == null || v == null) { 582 return; 583 } 584 String key = k.toLowerCase(Locale.ROOT); 585 switch (key) { 586 case "annotations" -> builder.annotations(Boolean.parseBoolean(v)); 587 case "additional_instructions" -> builder.additionalInstructions(v); 588 case "azure_deployment_name" -> builder.azureDeploymentName(v); 589 case "azure_embedding_deployment_name" -> builder.azureEmbeddingDeploymentName(v); 590 case "azure_resource_name" -> builder.azureResourceName(v); 591 case "case_sensitive_values" -> builder.caseSensitiveValues(Boolean.parseBoolean(v)); 592 case "comments" -> builder.comments(Boolean.parseBoolean(v)); 593 case "constraints" -> builder.constraints(Boolean.parseBoolean(v)); 594 case "conversation" -> builder.conversation(Boolean.parseBoolean(v)); 595 case "conversation_length" -> builder.conversationLength(Integer.parseInt(v)); 596 case "credential_name" -> builder.credentialName(v); 597 case "embedding_model" -> builder.embeddingModel(v); 598 case "enable_custom_source_uri" -> builder.enableCustomSourceUri(Boolean.parseBoolean(v)); 599 case "enforce_object_list" -> builder.enforceObjectList(Boolean.parseBoolean(v)); 600 case "max_tokens" -> builder.maxTokens(Integer.parseInt(v)); 601 case "model" -> builder.model(v); 602 case "object_list" -> builder.objectList(v); 603 case "object_list_mode" -> builder.objectListMode(v); 604 case "oci_apiformat" -> builder.ociApiformat(v); 605 case "oci_compartment_id" -> builder.ociCompartmentId(v); 606 case "oci_endpoint_id" -> builder.ociEndpointId(v); 607 case "oci_runtimetype" -> builder.ociRuntimetype(v); 608 case "provider" -> builder.provider(v); 609 case "provider_endpoint" -> builder.providerEndpoint(v); 610 case "region" -> builder.region(v); 611 case "role" -> builder.role(v); 612 case "seed" -> builder.seed(Long.parseLong(v)); 613 case "stop_tokens" -> builder.stopTokens(parseStopTokens(v)); 614 case "temperature" -> builder.temperature(Double.parseDouble(v)); 615 case "vector_index_name" -> builder.vectorIndexName(v); 616 case "source_language" -> builder.sourceLanguage(v); 617 case "target_language" -> builder.targetLanguage(v); 618 default -> builder.customAttribute(k, v); 619 } 620 }); 621 return builder.build(); 622 } 623 624 /** 625 * Adds a non-null profile attribute value to the output map. 626 * 627 * @param map destination attribute map 628 * @param key DBMS_CLOUD_AI attribute name 629 * @param value value to stringify and add 630 */ 631 private static void putIfNotNull(Map<String, String> map, String key, Object value) { 632 if (value != null) { 633 map.put(key, String.valueOf(value)); 634 } 635 } 636 637 /** 638 * Adds stop tokens as JSON array text so string-valued attribute maps can 639 * preserve token boundaries. 640 * 641 * @param map destination attribute map 642 * @param stopTokens stop-token list 643 */ 644 private static void putStopTokensIfNotNull(Map<String, String> map, List<String> stopTokens) { 645 if (stopTokens == null) { 646 return; 647 } 648 try { 649 map.put("stop_tokens", new ObjectMapper().writeValueAsString(stopTokens)); 650 } catch (Exception e) { 651 throw new IllegalStateException("Failed to serialize stopTokens", e); 652 } 653 } 654 655 /** 656 * Parses a stop_tokens attribute value serialized as a JSON array. 657 * 658 * @param value stop_tokens attribute value 659 * @return parsed stop-token list 660 */ 661 private static List<String> parseStopTokens(String value) { 662 if (value == null || value.isBlank()) { 663 return null; 664 } 665 try { 666 ObjectMapper mapper = new ObjectMapper(); 667 var root = mapper.readTree(value); 668 if (!root.isArray()) { 669 throw new IllegalArgumentException("stop_tokens must be a JSON array"); 670 } 671 List<String> parsedStopTokens = new ArrayList<>(); 672 for (var node : root) { 673 if (!node.isTextual()) { 674 throw new IllegalArgumentException("stop_tokens must contain only string values"); 675 } 676 parsedStopTokens.add(node.asText()); 677 } 678 return parsedStopTokens; 679 } catch (IllegalArgumentException e) { 680 throw e; 681 } catch (Exception e) { 682 throw new IllegalArgumentException("stop_tokens must be valid JSON array text", e); 683 } 684 } 685 686 /** 687 * Serializes the profile attributes using snake_case JSON names. 688 * 689 * @return JSON representation of this ProfileAttributes instance 690 */ 691 public String toJson() { 692 ObjectMapper mapper = new ObjectMapper(); 693 try { 694 mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); 695 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 696 return mapper.writeValueAsString(this); 697 } catch (Exception e) { 698 throw new IllegalStateException("Failed to serialize ProfileAttributes to JSON", e); 699 } 700 } 701 702 /** 703 * Builder for {@link ProfileAttributes}. 704 */ 705 public static final class Builder { 706 /** Annotation metadata flag being assembled. */ 707 private Boolean annotations; 708 /** Additional prompt instructions being assembled. */ 709 private String additionalInstructions; 710 /** Azure OpenAI deployment name being assembled. */ 711 private String azureDeploymentName; 712 /** Azure embedding deployment name being assembled. */ 713 private String azureEmbeddingDeploymentName; 714 /** Azure resource name being assembled. */ 715 private String azureResourceName; 716 /** Case-sensitive value matching flag being assembled. */ 717 private Boolean caseSensitiveValues; 718 /** Table/column comments flag being assembled. */ 719 private Boolean comments; 720 /** Referential constraints flag being assembled. */ 721 private Boolean constraints; 722 /** Conversation support flag being assembled. */ 723 private Boolean conversation; 724 /** Conversation context length being assembled. */ 725 private Integer conversationLength; 726 /** Provider credential name being assembled. */ 727 private String credentialName; 728 /** Embedding model name being assembled. */ 729 private String embeddingModel; 730 /** Custom source URI flag being assembled. */ 731 private Boolean enableCustomSourceUri; 732 /** Object list enforcement flag being assembled. */ 733 private Boolean enforceObjectList; 734 /** Maximum output token count being assembled. */ 735 private Integer maxTokens; 736 /** Provider model name being assembled. */ 737 private String model; 738 /** Object list JSON being assembled. */ 739 private String objectList; 740 /** Object list mode being assembled. */ 741 private String objectListMode; 742 /** OCI API format being assembled. */ 743 private String ociApiformat; 744 /** OCI compartment OCID being assembled. */ 745 private String ociCompartmentId; 746 /** OCI endpoint OCID being assembled. */ 747 private String ociEndpointId; 748 /** OCI runtime type being assembled. */ 749 private String ociRuntimetype; 750 /** Provider name being assembled. */ 751 private String provider; 752 /** Provider endpoint being assembled. */ 753 private String providerEndpoint; 754 /** Provider region being assembled. */ 755 private String region; 756 /** Role prompt being assembled. */ 757 private String role; 758 /** Deterministic sampling seed being assembled. */ 759 private Long seed; 760 /** Stop token list being assembled. */ 761 private List<String> stopTokens; 762 /** Provider temperature being assembled. */ 763 private Double temperature; 764 /** Unmodeled attributes accepted for forward compatibility. */ 765 private Map<String, String> customAttributes; 766 /** Vector index name being assembled. */ 767 private String vectorIndexName; 768 /** Translation source language being assembled. */ 769 private String sourceLanguage; 770 /** Translation target language being assembled. */ 771 private String targetLanguage; 772 /** Provider profile shortcut that populated this builder. */ 773 private ProviderProfile providerProfile; 774 775 private Builder() { 776 this.customAttributes = new HashMap<>(); 777 } 778 779 /** 780 * Sets whether table/column annotations are included in metadata. 781 * 782 * @param annotations annotation metadata flag 783 * @return this builder instance 784 */ 785 public Builder annotations(Boolean annotations) { 786 this.annotations = annotations; 787 return this; 788 } 789 790 /** 791 * Sets additional instructions included in Select AI prompts. 792 * 793 * @param additionalInstructions additional prompt instructions 794 * @return this builder instance 795 */ 796 public Builder additionalInstructions(String additionalInstructions) { 797 this.additionalInstructions = additionalInstructions; 798 return this; 799 } 800 801 /** 802 * Sets the Azure OpenAI deployment name for the generation model. 803 * 804 * @param azureDeploymentName Azure deployment name 805 * @return this builder instance 806 */ 807 public Builder azureDeploymentName(String azureDeploymentName) { 808 this.azureDeploymentName = azureDeploymentName; 809 return this; 810 } 811 812 /** 813 * Sets the Azure OpenAI deployment name for the embedding model. 814 * 815 * @param azureEmbeddingDeploymentName Azure embedding deployment name 816 * @return this builder instance 817 */ 818 public Builder azureEmbeddingDeploymentName(String azureEmbeddingDeploymentName) { 819 this.azureEmbeddingDeploymentName = azureEmbeddingDeploymentName; 820 return this; 821 } 822 823 /** 824 * Sets the Azure OpenAI resource name. 825 * 826 * @param azureResourceName Azure resource name 827 * @return this builder instance 828 */ 829 public Builder azureResourceName(String azureResourceName) { 830 this.azureResourceName = azureResourceName; 831 return this; 832 } 833 834 /** 835 * Sets whether generated SQL value matching is case-sensitive. 836 * 837 * @param caseSensitiveValues case-sensitive values flag 838 * @return this builder instance 839 */ 840 public Builder caseSensitiveValues(Boolean caseSensitiveValues) { 841 this.caseSensitiveValues = caseSensitiveValues; 842 return this; 843 } 844 845 /** 846 * Sets whether table and column comments are included in metadata. 847 * 848 * @param comments comments metadata flag 849 * @return this builder instance 850 */ 851 public Builder comments(Boolean comments) { 852 this.comments = comments; 853 return this; 854 } 855 856 /** 857 * Sets whether referential constraints are included in metadata. 858 * 859 * @param constraints constraints metadata flag 860 * @return this builder instance 861 */ 862 public Builder constraints(Boolean constraints) { 863 this.constraints = constraints; 864 return this; 865 } 866 867 /** 868 * Sets whether conversation history is enabled for the profile. 869 * 870 * @param conversation conversation flag 871 * @return this builder instance 872 */ 873 public Builder conversation(Boolean conversation) { 874 this.conversation = conversation; 875 return this; 876 } 877 878 /** 879 * Sets how many conversation turns are retained for context. 880 * 881 * @param conversationLength positive conversation context length 882 * @return this builder instance 883 */ 884 public Builder conversationLength(Integer conversationLength) { 885 if (conversationLength != null && conversationLength <= 0) { 886 throw new IllegalArgumentException("conversationLength must be greater than 0"); 887 } 888 this.conversationLength = conversationLength; 889 return this; 890 } 891 892 /** 893 * Sets the database credential used for provider API calls. 894 * 895 * @param credentialName credential name 896 * @return this builder instance 897 */ 898 public Builder credentialName(String credentialName) { 899 this.credentialName = credentialName; 900 return this; 901 } 902 903 /** 904 * Sets the embedding model name. 905 * 906 * @param embeddingModel embedding model name 907 * @return this builder instance 908 */ 909 public Builder embeddingModel(String embeddingModel) { 910 this.embeddingModel = embeddingModel; 911 return this; 912 } 913 914 /** 915 * Sets whether custom source URI metadata is enabled. 916 * 917 * @param enableCustomSourceUri custom source URI flag 918 * @return this builder instance 919 */ 920 public Builder enableCustomSourceUri(Boolean enableCustomSourceUri) { 921 this.enableCustomSourceUri = enableCustomSourceUri; 922 return this; 923 } 924 925 /** 926 * Sets whether generated SQL is restricted to the object list. 927 * 928 * @param enforceObjectList object list enforcement flag 929 * @return this builder instance 930 */ 931 public Builder enforceObjectList(Boolean enforceObjectList) { 932 this.enforceObjectList = enforceObjectList; 933 return this; 934 } 935 936 /** 937 * Sets the maximum generated output tokens. 938 * 939 * @param maxTokens positive token limit 940 * @return this builder instance 941 */ 942 public Builder maxTokens(Integer maxTokens) { 943 if (maxTokens != null && maxTokens <= 0) { 944 throw new IllegalArgumentException("maxTokens must be greater than 0"); 945 } 946 this.maxTokens = maxTokens; 947 return this; 948 } 949 950 /** 951 * Sets the provider model identifier. 952 * 953 * @param model provider model identifier 954 * @return this builder instance 955 */ 956 public Builder model(String model) { 957 this.model = model; 958 return this; 959 } 960 961 /** 962 * Sets the object list JSON used to constrain metadata. 963 * 964 * @param objectList JSON array containing object descriptors 965 * @return this builder instance 966 */ 967 public Builder objectList(String objectList) { 968 this.objectList = objectList; 969 return this; 970 } 971 972 /** 973 * Sets the object-list selection mode used for NL2SQL processing. 974 * 975 * <p>A {@code null} value leaves the object-list mode unset. A non-null value 976 * must correspond to an object-list mode supported by the SDK; otherwise, 977 * this method throws an {@link IllegalArgumentException}.</p> 978 * 979 * @param objectListMode object-list mode, or {@code null} to leave the mode unset 980 * @return this builder instance 981 * @throws IllegalArgumentException if {@code objectListMode} is non-null and 982 * does not correspond to a supported object-list mode 983 */ 984 public Builder objectListMode(String objectListMode) { 985 ObjectListMode parsedObjectListMode = 986 ObjectListMode.fromValue(objectListMode); 987 this.objectListMode = parsedObjectListMode == null ? null : parsedObjectListMode.getValue(); 988 return this; 989 } 990 991 /** 992 * Sets the object-list selection mode used for NL2SQL processing. 993 * 994 * @param objectListMode object-list mode 995 * @return this builder instance 996 */ 997 public Builder objectListMode(ObjectListMode objectListMode) { 998 this.objectListMode = objectListMode == null ? null : objectListMode.getValue(); 999 return this; 1000 } 1001 1002 /** 1003 * Sets the OCI Generative AI API format. 1004 * 1005 * @param ociApiformat OCI API format, such as COHERE or GENERIC 1006 * @return this builder instance 1007 */ 1008 public Builder ociApiformat(String ociApiformat) { 1009 OciApiFormat parsedOciApiFormat = OciApiFormat.fromValue(ociApiformat); 1010 this.ociApiformat = parsedOciApiFormat == null ? null : parsedOciApiFormat.getValue(); 1011 return this; 1012 } 1013 1014 /** 1015 * Sets the OCI Generative AI API format. 1016 * 1017 * @param ociApiFormat OCI API format 1018 * @return this builder instance 1019 */ 1020 public Builder ociApiformat(OciApiFormat ociApiFormat) { 1021 this.ociApiformat = ociApiFormat == null ? null : ociApiFormat.getValue(); 1022 return this; 1023 } 1024 1025 /** 1026 * Sets the OCI compartment OCID. 1027 * 1028 * @param ociCompartmentId OCI compartment OCID 1029 * @return this builder instance 1030 */ 1031 public Builder ociCompartmentId(String ociCompartmentId) { 1032 this.ociCompartmentId = ociCompartmentId; 1033 return this; 1034 } 1035 1036 /** 1037 * Sets the OCI dedicated endpoint OCID. 1038 * 1039 * @param ociEndpointId OCI endpoint OCID 1040 * @return this builder instance 1041 */ 1042 public Builder ociEndpointId(String ociEndpointId) { 1043 this.ociEndpointId = ociEndpointId; 1044 return this; 1045 } 1046 1047 /** 1048 * Sets the OCI runtime type attribute. 1049 * 1050 * @param ociRuntimetype OCI runtime type 1051 * @return this builder instance 1052 */ 1053 public Builder ociRuntimetype(String ociRuntimetype) { 1054 this.ociRuntimetype = ociRuntimetype; 1055 return this; 1056 } 1057 1058 /** 1059 * Sets the AI provider for the profile. 1060 * 1061 * <p>A {@code null} value leaves the provider unset. A non-null value must 1062 * correspond to a provider supported by the SDK; otherwise, this method 1063 * throws an {@link IllegalArgumentException}.</p> 1064 * 1065 * @param provider provider name, or {@code null} to leave the provider unset 1066 * @return this builder instance 1067 * @throws IllegalArgumentException if {@code provider} is non-null and does 1068 * not correspond to a supported provider 1069 */ 1070 public Builder provider(String provider) { 1071 if (provider == null) { 1072 this.provider = null; 1073 return this; 1074 } 1075 1076 Provider parsedProvider = Provider.fromValue(provider); 1077 1078 if (parsedProvider == null) { 1079 throw new IllegalArgumentException( 1080 "Unsupported provider: " + provider); 1081 } 1082 1083 this.provider = parsedProvider.name(); 1084 return this; 1085 } 1086 1087 /** 1088 * Sets the provider endpoint host/path. 1089 * 1090 * @param providerEndpoint provider endpoint 1091 * @return this builder instance 1092 */ 1093 public Builder providerEndpoint(String providerEndpoint) { 1094 this.providerEndpoint = providerEndpoint; 1095 return this; 1096 } 1097 1098 /** 1099 * Sets the provider region. 1100 * 1101 * @param region provider region 1102 * @return this builder instance 1103 */ 1104 public Builder region(String region) { 1105 this.region = region; 1106 return this; 1107 } 1108 1109 /** 1110 * Sets the role prompt used by Select AI. 1111 * 1112 * @param role role prompt 1113 * @return this builder instance 1114 */ 1115 public Builder role(String role) { 1116 this.role = role; 1117 return this; 1118 } 1119 1120 /** 1121 * Sets the deterministic sampling seed. 1122 * 1123 * @param seed sampling seed 1124 * @return this builder instance 1125 */ 1126 public Builder seed(Long seed) { 1127 this.seed = seed; 1128 return this; 1129 } 1130 1131 /** 1132 * Sets stop tokens that terminate generation. 1133 * 1134 * @param stopTokens stop token list 1135 * @return this builder instance 1136 */ 1137 public Builder stopTokens(List<String> stopTokens) { 1138 this.stopTokens = stopTokens; 1139 return this; 1140 } 1141 1142 /** 1143 * Sets the provider sampling temperature. 1144 * 1145 * @param temperature non-negative temperature 1146 * @return this builder instance 1147 */ 1148 public Builder temperature(Double temperature) { 1149 if (temperature != null && temperature < 0) { 1150 throw new IllegalArgumentException("temperature must be a non-negative float"); 1151 } 1152 this.temperature = temperature; 1153 return this; 1154 } 1155 1156 /** 1157 * Sets the vector index name associated with the profile. 1158 * 1159 * @param vectorIndexName Oracle SQL identifier for the vector index 1160 * @return this builder instance 1161 */ 1162 public Builder vectorIndexName(String vectorIndexName) { 1163 this.vectorIndexName = vectorIndexName; 1164 return this; 1165 } 1166 1167 /** 1168 * Sets the source language for translation. 1169 * 1170 * @param sourceLanguage source language name or code 1171 * @return this builder instance 1172 */ 1173 public Builder sourceLanguage(String sourceLanguage) { 1174 this.sourceLanguage = sourceLanguage; 1175 return this; 1176 } 1177 1178 /** 1179 * Sets the target language for translation. 1180 * 1181 * @param targetLanguage target language name or code 1182 * @return this builder instance 1183 */ 1184 public Builder targetLanguage(String targetLanguage) { 1185 this.targetLanguage = targetLanguage; 1186 return this; 1187 } 1188 1189 /** 1190 * Applies a provider profile shortcut to this builder. 1191 * 1192 * @param providerProfile provider profile to apply 1193 * @return this builder instance 1194 */ 1195 public Builder providerProfile(ProviderProfile providerProfile) { 1196 if (providerProfile == null) { 1197 return this; 1198 } 1199 this.providerProfile = providerProfile; 1200 providerProfile.applyTo(this); 1201 return this; 1202 } 1203 1204 /** 1205 * Accepts an unmodeled profile attribute for forward compatibility. 1206 * <p> 1207 * Current typed JSON serialization only emits attributes represented by 1208 * this SDK. This method prevents unknown database attributes from failing a 1209 * read/round-trip through {@link #fromAttributeMap(Map)}. 1210 * 1211 * @param key DBMS_CLOUD_AI attribute name 1212 * @param value attribute value 1213 * @return this builder instance 1214 */ 1215 public Builder customAttribute(String key, String value) { 1216 if (key != null && value != null) { 1217 this.customAttributes.put(key, value); 1218 } 1219 return this; 1220 } 1221 1222 /** 1223 * Builds immutable profile attributes. 1224 * 1225 * @return immutable ProfileAttributes instance built from current builder state 1226 */ 1227 public ProfileAttributes build() { 1228 return new ProfileAttributes(this); 1229 } 1230 } 1231}