diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index cbe625271..000000000 --- a/.editorconfig +++ /dev/null @@ -1,305 +0,0 @@ -# To learn more about .editorconfig see https://aka.ms/editorconfigdocs -############################### -# Core EditorConfig Options # -############################### -root = true -# All files -[*] -indent_style = space -end_of_line = lf - -# XML project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] -indent_size = 2 - -# XML config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] -indent_size = 2 - -# YAML config files -[*.{yml,yaml}] -tab_width = 2 -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -# JSON config files -[*.json] -tab_width = 2 -indent_size = 2 -insert_final_newline = false -trim_trailing_whitespace = true - -# Stylesheet files -[*.{css,scss,sass,less}] -insert_final_newline = true -trim_trailing_whitespace = true -tab_width = 4 -indent_size = 4 - -# Code files -[*.{cs,csx,vb,vbx}] -tab_width = 4 -indent_size = 4 -insert_final_newline = true -trim_trailing_whitespace = true -charset = utf-8-bom -file_header_template = Copyright (c) Microsoft. All rights reserved. - -############################### -# Java Coding Conventions # -############################### -[*.java] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = false -tab_width = 4 -ij_formatter_off_tag = @formatter:off -ij_formatter_on_tag = @formatter:on -ij_smart_tabs = false -ij_visual_guides = none - -max_line_length = 100 -ij_continuation_indent_size = 4 -ij_formatter_tags_enabled = false -ij_wrap_on_typing = false - -ij_java_align_consecutive_assignments = false -ij_java_align_consecutive_variable_declarations = false -ij_java_align_group_field_declarations = false -ij_java_align_multiline_annotation_parameters = false -ij_java_align_multiline_array_initializer_expression = false -ij_java_align_multiline_assignment = false -ij_java_align_multiline_binary_operation = false -ij_java_align_multiline_chained_methods = false -ij_java_align_multiline_extends_list = false -ij_java_align_multiline_for = false -ij_java_align_multiline_method_parentheses = false -ij_java_align_multiline_parameters = false -ij_java_align_multiline_parameters_in_calls = false -ij_java_align_multiline_parenthesized_expression = false -ij_java_align_multiline_resources = false -ij_java_align_multiline_ternary_operation = false -ij_java_align_multiline_throws_list = false -ij_java_align_subsequent_simple_methods = false -ij_java_align_throws_keyword = false -ij_java_annotation_parameter_wrap = off -ij_java_array_initializer_new_line_after_left_brace = false -ij_java_array_initializer_right_brace_on_new_line = false -ij_java_array_initializer_wrap = normal -ij_java_assert_statement_colon_on_next_line = false -ij_java_assert_statement_wrap = off -ij_java_assignment_wrap = off -ij_java_binary_operation_sign_on_next_line = true -ij_java_binary_operation_wrap = normal -ij_java_blank_lines_after_anonymous_class_header = 0 -ij_java_blank_lines_after_class_header = 1 -ij_java_blank_lines_after_imports = 1 -ij_java_blank_lines_after_package = 1 -ij_java_blank_lines_around_class = 1 -ij_java_blank_lines_around_field = 0 -ij_java_blank_lines_around_field_in_interface = 0 -ij_java_blank_lines_around_initializer = 1 -ij_java_blank_lines_around_method = 1 -ij_java_blank_lines_around_method_in_interface = 1 -ij_java_blank_lines_before_class_end = 0 -ij_java_blank_lines_before_imports = 1 -ij_java_blank_lines_before_method_body = 0 -ij_java_blank_lines_before_package = 0 -ij_java_block_brace_style = end_of_line -ij_java_block_comment_at_first_column = true -ij_java_call_parameters_new_line_after_left_paren = false -ij_java_call_parameters_right_paren_on_new_line = false -ij_java_call_parameters_wrap = normal -ij_java_case_statement_on_separate_line = true -ij_java_catch_on_new_line = false -ij_java_class_annotation_wrap = split_into_lines -ij_java_class_brace_style = end_of_line -ij_java_class_count_to_use_import_on_demand = 999 -ij_java_class_names_in_javadoc = 1 -ij_java_do_not_indent_top_level_class_members = false -ij_java_do_not_wrap_after_single_annotation = false -ij_java_do_while_brace_force = always -ij_java_doc_add_blank_line_after_description = true -ij_java_doc_add_blank_line_after_param_comments = false -ij_java_doc_add_blank_line_after_return = false -ij_java_doc_add_p_tag_on_empty_lines = true -ij_java_doc_align_exception_comments = true -ij_java_doc_align_param_comments = true -ij_java_doc_do_not_wrap_if_one_line = false -ij_java_doc_enable_formatting = true -ij_java_doc_enable_leading_asterisks = true -ij_java_doc_indent_on_continuation = false -ij_java_doc_keep_empty_lines = true -ij_java_doc_keep_empty_parameter_tag = true -ij_java_doc_keep_empty_return_tag = true -ij_java_doc_keep_empty_throws_tag = true -ij_java_doc_keep_invalid_tags = true -ij_java_doc_param_description_on_new_line = false -ij_java_doc_preserve_line_breaks = false -ij_java_doc_use_throws_not_exception_tag = true -ij_java_else_on_new_line = false -ij_java_entity_dd_suffix = EJB -ij_java_entity_eb_suffix = Bean -ij_java_entity_hi_suffix = Home -ij_java_entity_lhi_prefix = Local -ij_java_entity_lhi_suffix = Home -ij_java_entity_li_prefix = Local -ij_java_entity_pk_class = java.lang.String -ij_java_entity_vo_suffix = VO -ij_java_enum_constants_wrap = off -ij_java_extends_keyword_wrap = off -ij_java_extends_list_wrap = normal -ij_java_field_annotation_wrap = split_into_lines -ij_java_finally_on_new_line = false -ij_java_for_brace_force = always -ij_java_for_statement_new_line_after_left_paren = false -ij_java_for_statement_right_paren_on_new_line = false -ij_java_for_statement_wrap = normal -ij_java_generate_final_locals = false -ij_java_generate_final_parameters = false -ij_java_if_brace_force = always -ij_java_imports_layout = $*, |, * -ij_java_indent_case_from_switch = true -ij_java_insert_inner_class_imports = true -ij_java_insert_override_annotation = true -ij_java_keep_blank_lines_before_right_brace = 2 -ij_java_keep_blank_lines_between_package_declaration_and_header = 2 -ij_java_keep_blank_lines_in_code = 1 -ij_java_keep_blank_lines_in_declarations = 2 -ij_java_keep_control_statement_in_one_line = false -ij_java_keep_first_column_comment = true -ij_java_keep_indents_on_empty_lines = false -ij_java_keep_line_breaks = true -ij_java_keep_multiple_expressions_in_one_line = false -ij_java_keep_simple_blocks_in_one_line = false -ij_java_keep_simple_classes_in_one_line = false -ij_java_keep_simple_lambdas_in_one_line = false -ij_java_keep_simple_methods_in_one_line = false -ij_java_lambda_brace_style = end_of_line -ij_java_layout_static_imports_separately = true -ij_java_line_comment_add_space = false -ij_java_line_comment_at_first_column = true -ij_java_message_dd_suffix = EJB -ij_java_message_eb_suffix = Bean -ij_java_method_annotation_wrap = split_into_lines -ij_java_method_brace_style = end_of_line -ij_java_method_call_chain_wrap = normal -ij_java_method_parameters_new_line_after_left_paren = false -ij_java_method_parameters_right_paren_on_new_line = false -ij_java_method_parameters_wrap = normal -ij_java_modifier_list_wrap = false -ij_java_names_count_to_use_import_on_demand = 999 -ij_java_parameter_annotation_wrap = off -ij_java_parentheses_expression_new_line_after_left_paren = false -ij_java_parentheses_expression_right_paren_on_new_line = false -ij_java_place_assignment_sign_on_next_line = false -ij_java_prefer_longer_names = true -ij_java_prefer_parameters_wrap = false -ij_java_repeat_synchronized = true -ij_java_replace_instanceof_and_cast = false -ij_java_replace_null_check = true -ij_java_replace_sum_lambda_with_method_ref = true -ij_java_resource_list_new_line_after_left_paren = false -ij_java_resource_list_right_paren_on_new_line = false -ij_java_resource_list_wrap = off -ij_java_session_dd_suffix = EJB -ij_java_session_eb_suffix = Bean -ij_java_session_hi_suffix = Home -ij_java_session_lhi_prefix = Local -ij_java_session_lhi_suffix = Home -ij_java_session_li_prefix = Local -ij_java_session_si_suffix = Service -ij_java_space_after_closing_angle_bracket_in_type_argument = false -ij_java_space_after_colon = true -ij_java_space_after_comma = true -ij_java_space_after_comma_in_type_arguments = true -ij_java_space_after_for_semicolon = true -ij_java_space_after_quest = true -ij_java_space_after_type_cast = true -ij_java_space_before_annotation_array_initializer_left_brace = false -ij_java_space_before_annotation_parameter_list = false -ij_java_space_before_array_initializer_left_brace = false -ij_java_space_before_catch_keyword = true -ij_java_space_before_catch_left_brace = true -ij_java_space_before_catch_parentheses = true -ij_java_space_before_class_left_brace = true -ij_java_space_before_colon = true -ij_java_space_before_colon_in_foreach = true -ij_java_space_before_comma = false -ij_java_space_before_do_left_brace = true -ij_java_space_before_else_keyword = true -ij_java_space_before_else_left_brace = true -ij_java_space_before_finally_keyword = true -ij_java_space_before_finally_left_brace = true -ij_java_space_before_for_left_brace = true -ij_java_space_before_for_parentheses = true -ij_java_space_before_for_semicolon = false -ij_java_space_before_if_left_brace = true -ij_java_space_before_if_parentheses = true -ij_java_space_before_method_call_parentheses = false -ij_java_space_before_method_left_brace = true -ij_java_space_before_method_parentheses = false -ij_java_space_before_opening_angle_bracket_in_type_parameter = false -ij_java_space_before_quest = true -ij_java_space_before_switch_left_brace = true -ij_java_space_before_switch_parentheses = true -ij_java_space_before_synchronized_left_brace = true -ij_java_space_before_synchronized_parentheses = true -ij_java_space_before_try_left_brace = true -ij_java_space_before_try_parentheses = true -ij_java_space_before_type_parameter_list = false -ij_java_space_before_while_keyword = true -ij_java_space_before_while_left_brace = true -ij_java_space_before_while_parentheses = true -ij_java_space_inside_one_line_enum_braces = false -ij_java_space_within_empty_array_initializer_braces = false -ij_java_space_within_empty_method_call_parentheses = false -ij_java_space_within_empty_method_parentheses = false -ij_java_spaces_around_additive_operators = true -ij_java_spaces_around_assignment_operators = true -ij_java_spaces_around_bitwise_operators = true -ij_java_spaces_around_equality_operators = true -ij_java_spaces_around_lambda_arrow = true -ij_java_spaces_around_logical_operators = true -ij_java_spaces_around_method_ref_dbl_colon = false -ij_java_spaces_around_multiplicative_operators = true -ij_java_spaces_around_relational_operators = true -ij_java_spaces_around_shift_operators = true -ij_java_spaces_around_type_bounds_in_type_parameters = true -ij_java_spaces_around_unary_operator = false -ij_java_spaces_within_angle_brackets = false -ij_java_spaces_within_annotation_parentheses = false -ij_java_spaces_within_array_initializer_braces = false -ij_java_spaces_within_braces = false -ij_java_spaces_within_brackets = false -ij_java_spaces_within_cast_parentheses = false -ij_java_spaces_within_catch_parentheses = false -ij_java_spaces_within_for_parentheses = false -ij_java_spaces_within_if_parentheses = false -ij_java_spaces_within_method_call_parentheses = false -ij_java_spaces_within_method_parentheses = false -ij_java_spaces_within_parentheses = false -ij_java_spaces_within_switch_parentheses = false -ij_java_spaces_within_synchronized_parentheses = false -ij_java_spaces_within_try_parentheses = false -ij_java_spaces_within_while_parentheses = false -ij_java_special_else_if_treatment = true -ij_java_subclass_name_suffix = Impl -ij_java_ternary_operation_signs_on_next_line = true -ij_java_ternary_operation_wrap = normal -ij_java_test_name_suffix = Test -ij_java_throws_keyword_wrap = normal -ij_java_throws_list_wrap = off -ij_java_use_external_annotations = false -ij_java_use_fq_class_names = false -ij_java_use_single_class_imports = true -ij_java_variable_annotation_wrap = off -ij_java_visibility = public -ij_java_while_brace_force = always -ij_java_while_on_new_line = false -ij_java_wrap_comments = true -ij_java_wrap_first_method_in_call_chain = false -ij_java_wrap_long_lines = false diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index b5845d148..000000000 --- a/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# Auto-detect text files, ensure they use LF. -* text=auto eol=lf working-tree-encoding=UTF-8 - -# Bash scripts -*.sh text eol=lf -*.cmd text eol=crlf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index d6e7dac3f..000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# @microsoft/octo-semantickernel-pr-java owns any files in the java -# directory at the root of the repository and any of its -# subdirectories. -/ @microsoft/octo-semantickernel-pr-java diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6f7815004..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: 'Bug: ' -labels: ["bug", "triage"] -projects: ["semantic-kernel"] -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Maven** - - Version: [e.g. 1.1.5] - - Dependencies: list of semantic-kernel related dependencies in your `pom.xml` - -**Platform** - - IDE: [e.g. IntelliJ, Eclipse, VS Code] - - JDK version: [e.g. JDK 11.0.17] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_graduation.md b/.github/ISSUE_TEMPLATE/feature_graduation.md deleted file mode 100644 index 37d207ea1..000000000 --- a/.github/ISSUE_TEMPLATE/feature_graduation.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Feature graduation -about: Plan the graduation of an experimental feature -title: 'Graduate XXX feature' -labels: ["feature_graduation"] -projects: ["semantic-kernel"] -assignees: '' - ---- - ---- -name: Feature graduation -about: Plan the graduation of an experimental feature - ---- - -Checklist to be completed when graduating an experimental feature - -- [ ] Notify PM's and EM's that feature is read for graduation -- [ ] Contact PM for list of sample use cases -- [ ] Verify there are sample implementations​ for each of the use cases -- [ ] Verify telemetry and logging are complete -- [ ] ​Verify API docs are complete and arrange to have them published -- [ ] Make appropriate updates to Learn docs​ -- [ ] Make appropriate updates to Concept samples -- [ ] Male appropriate updates to Blog posts -- [ ] Verify there are no serious open Issues​​ -- [ ] Update table in EXPERIMENTS.md -- [ ] Remove SKEXP​ flag from the experimental code diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index ca7db8088..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: 'New Feature: ' -labels: '["triage", "enhancement"]' -projects: ["semantic-kernel"] -assignees: '' - ---- - ---- -name: Feature request -about: Suggest an idea for this project - ---- - - - - - - diff --git a/.github/_typos.toml b/.github/_typos.toml deleted file mode 100644 index c101713b6..000000000 --- a/.github/_typos.toml +++ /dev/null @@ -1,45 +0,0 @@ -# Typos configuration file -# -# Info: https://github.com/marketplace/actions/typos-action -# Install: brew install typos-cli -# Install: conda install typos -# Run: typos -c .github/_typos.toml - -[files] -extend-exclude = [ - "_typos.toml", - "package-lock.json", - "*.bicep", - "encoder.json", - "vocab.bpe", - "CodeTokenizerTests.cs", - "test_code_tokenizer.py", - "*response.json", - "samples/semantickernel-demos/sk-presidio-sample/README.md" -] - -[default.extend-words] -ACI = "ACI" # Azure Container Instance -exercize = "exercize" # test typos -gramatical = "gramatical" # test typos -Guid = "Guid" # Globally Unique Identifier -HD = "HD" # Test header value -EOF = "EOF" # End of File -ans = "ans" # Short for answers -arange = "arange" # Method in Python numpy package -prompty = "prompty" # prompty is a format name. -ist = "ist" # German language -Prelease = "Prelease" # Prelease is a format name. - -[default.extend-identifiers] -ags = "ags" # Azure Graph Service - -[type.jupyter] -extend-ignore-re = [ - '"[A-Fa-f0-9]{8}"', # cell id strings -] - -[type.msbuild] -extend-ignore-re = [ - 'Version=".*"', # ignore package version numbers -] diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 97b4f6647..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,58 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - # Maintain dependencies for nuget - - package-ecosystem: "nuget" - directory: "dotnet/" - schedule: - interval: "weekly" - day: "monday" - ignore: - # For all System.* and Microsoft.Extensions/Bcl.* packages, ignore all major version updates - - dependency-name: "System.*" - update-types: ["version-update:semver-major"] - - dependency-name: "Microsoft.Extensions.*" - update-types: ["version-update:semver-major"] - - dependency-name: "Microsoft.Bcl.*" - update-types: ["version-update:semver-major"] - - dependency-name: "Moq" - labels: - - ".NET" - - "dependencies" - - # Maintain dependencies for nuget - - package-ecosystem: "nuget" - directory: "samples/dotnet" - schedule: - interval: "weekly" - day: "monday" - - # Maintain dependencies for npm - - package-ecosystem: "npm" - directory: "samples/apps" - schedule: - interval: "weekly" - day: "monday" - - # Maintain dependencies for pip - - package-ecosystem: "pip" - directory: "python/" - schedule: - interval: "weekly" - day: "monday" - labels: - - "python" - - "dependencies" - - # Maintain dependencies for github-actions - - package-ecosystem: "github-actions" - # Workflow files stored in the - # default location of `.github/workflows` - directory: "/" - schedule: - interval: "weekly" - day: "monday" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 38e62262d..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,23 +0,0 @@ -### Motivation and Context - - - -### Description - - - -### Contribution Checklist - - - -- [ ] The code builds clean without any errors or warnings -- [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations -- [ ] All unit tests pass, and I have added new tests where possible -- [ ] I didn't break anyone :smile: diff --git a/.github/workflows/close-inactive-issues.yml b/.github/workflows/close-inactive-issues.yml deleted file mode 100644 index 4e6ebccef..000000000 --- a/.github/workflows/close-inactive-issues.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Close inactive issues -on: - schedule: - - cron: "30 1 * * *" - -jobs: - close-issues: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: actions/stale@v10 - with: - days-before-issue-stale: 90 - days-before-issue-close: 14 - stale-issue-label: "stale" - stale-issue-message: "This issue is stale because it has been open for 90 days with no activity." - close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." - days-before-pr-stale: -1 - days-before-pr-close: -1 - repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index dee4d1c46..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,78 +0,0 @@ -# CodeQL is the code analysis engine developed by GitHub to automate security checks. -# The results are shown as code scanning alerts in GitHub. For more details, visit: -# https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning-with-codeql - -name: "CodeQL" - -on: - push: - branches: ["main"] - schedule: - - cron: "17 11 * * 2" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["java"] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Use only 'java' to analyze code written in Java, Kotlin or both - # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - if: ${{ matrix.language != 'java' }} - uses: github/codeql-action/autobuild@v4 - - - name: Setup JDK - uses: actions/setup-java@v5 - if: ${{ matrix.language == 'java' }} - with: - java-version: 17 - distribution: microsoft - cache: maven - - - name: Build Java - if: ${{ matrix.language == 'java' }} - run: ./mvnw -B -DskipTests -Pcompile-jdk17 clean install --file pom.xml - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml deleted file mode 100644 index 32b71f757..000000000 --- a/.github/workflows/java-build.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Build Java Semantic Kernel - -# Triggers the workflow on manual dispatch, push, and pull request events -# for the specified branches and paths -on: - workflow_dispatch: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -permissions: - contents: read - -jobs: - # Builds and tests the Java project - java-build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - # Defines a matrix strategy for JDK versions 8 and 17 - java-versions: [8, 17] - - name: Java CI on JDK${{ matrix.java-versions }} - - steps: - - name: Checkout - uses: actions/checkout@v6 - - # Need to use JDK 11 to build for JDK 8 - - name: Set JDK - id: set-jdk - shell: bash - run: | - if [[ ${{ matrix.java-versions }} == 8 ]]; then - echo "JDK_VERSION=11" >> $GITHUB_OUTPUT - else - version=${{ matrix.java-versions }} - echo "JDK_VERSION=$version" >> $GITHUB_OUTPUT - fi - - # Sets up the specified JDK version from the matrix - - uses: actions/setup-java@v5 - with: - java-version: ${{ steps.set-jdk.outputs.JDK_VERSION }} - distribution: microsoft - cache: maven - - # Builds the project with Maven using the matrix JDK version - - name: Build with Maven - run: ./mvnw -B -Pbug-check -DskipTests -Pcompile-jdk${{ matrix.java-versions }} clean install --file pom.xml - - # Runs tests with Maven using the matrix JDK version - - name: Run tests - run: ./mvnw -B -Pbug-check -Pcompile-jdk${{ matrix.java-versions }} test --file pom.xml - - # Uploads test artifacts for each JDK version - - uses: actions/upload-artifact@v6 - if: always() - with: - name: test_output_sk_jdk${{ matrix.java-versions }}u - path: ./**/target/surefire-reports/*Test.txt diff --git a/.github/workflows/java-integration-tests.yml b/.github/workflows/java-integration-tests.yml deleted file mode 100644 index 17edd75ed..000000000 --- a/.github/workflows/java-integration-tests.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Run Java Integration Tests and Samples - -on: - workflow_dispatch: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -permissions: - contents: read - -jobs: - java-integration-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - java-versions: [8, 17] - - name: Java Tests on JDK${{ matrix.java-versions }} - - steps: - - name: Checkout - uses: actions/checkout@v6 - - # Need to use JDK 11 to build for JDK 8 - - name: Set JDK - id: set-jdk - shell: bash - run: | - if [[ ${{ matrix.java-versions }} == 8 ]]; then - echo "JDK_VERSION=11" >> $GITHUB_OUTPUT - else - version=${{ matrix.java-versions }} - echo "JDK_VERSION=$version" >> $GITHUB_OUTPUT - fi - - - uses: actions/setup-java@v5 - with: - java-version: ${{ steps.set-jdk.outputs.JDK_VERSION }} - distribution: microsoft - cache: maven - - - name: Build with Maven - run: ./mvnw -B -Pwith-samples -Pbug-check -DskipTests -Pcompile-jdk${{ matrix.java-versions }} clean install --file pom.xml - if: ${{ matrix.java-versions >= 17 }} - - # API tests run on JDK 17+ - - name: Run integration tests - run: ../mvnw -B -Pbug-check clean install --file pom.xml - working-directory: api-test - env: - OPENAI_API_KEY: "" - AZURE_OPENAI_ENDPOINT: "" - AZURE_OPENAI_API_KEY: "" - AZURE_OPENAI_DEPLOYMENT_NAME: "" - if: ${{ matrix.java-versions >= 17 }} - - # Samples build on JDK 17+ - - name: Build semantic-kernel samples - run: ../mvnw -B clean install --file pom.xml - working-directory: samples - if: ${{ matrix.java-versions >= 17 }} diff --git a/.github/workflows/java-publish-package.yml b/.github/workflows/java-publish-package.yml deleted file mode 100644 index 8cc4e00c0..000000000 --- a/.github/workflows/java-publish-package.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Deploy Java Semantic Kernel Package - -# Triggers the workflow on merging a PR -on: - pull_request: - types: - - closed - branches: [ "main" ] - -permissions: - contents: read - packages: write - -jobs: - if_merged: - if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - - # Sets up the specified JDK version from the matrix - - uses: actions/setup-java@v5 - with: - java-version: 11 - distribution: microsoft - cache: maven - - - name: Build artifacts - run: ./mvnw -B -DskipTests -Pcompile-jdk8 -P-compile-jdk17 clean deploy --file pom.xml -DaltDeploymentRepository=local::file:///tmp/target/staging-deploy - - - name: Upload Artifacts - uses: actions/upload-artifact@v6 - with: - name: Artifacts - path: /tmp/target/staging-deploy - - - name: Deploy to github packages - run: ./mvnw -B -DskipTests -Pcompile-jdk8 -P-compile-jdk17 -Pgithub-packages clean deploy --file pom.xml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/label-issues.yml b/.github/workflows/label-issues.yml deleted file mode 100644 index cf901ade0..000000000 --- a/.github/workflows/label-issues.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Label issues -on: - issues: - types: - - reopened - - opened - -jobs: - label_issues: - name: "Issue: add labels" - if: ${{ github.event.action == 'opened' || github.event.action == 'reopened' }} - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }} - script: | - // Get the issue body and title - const body = context.payload.issue.body - let title = context.payload.issue.title - - // Define the labels array - let labels = ["triage"] - - // Check if the body or the title contains the word 'python' (case-insensitive) - if ((body != null && body.match(/python/i)) || (title != null && title.match(/python/i))) { - // Add the 'python' label to the array - labels.push("python") - } - - // Check if the body or the title contains the word 'java' (case-insensitive) - if ((body != null && body.match(/java/i)) || (title != null && title.match(/java/i))) { - // Add the 'java' label to the array - labels.push("java") - } - - // Check if the body or the title contains the words 'dotnet', '.net', 'c#' or 'csharp' (case-insensitive) - if ((body != null && body.match(/.net/i)) || (title != null && title.match(/.net/i)) || - (body != null && body.match(/dotnet/i)) || (title != null && title.match(/dotnet/i)) || - (body != null && body.match(/C#/i)) || (title != null && title.match(/C#/i)) || - (body != null && body.match(/csharp/i)) || (title != null && title.match(/csharp/i))) { - // Add the '.NET' label to the array - labels.push(".NET") - } - - // Add the labels to the issue - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: labels - }); diff --git a/.github/workflows/label-title-prefix.yml b/.github/workflows/label-title-prefix.yml deleted file mode 100644 index 81369deed..000000000 --- a/.github/workflows/label-title-prefix.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Label title prefix -on: - issues: - types: [labeled] - pull_request_target: - types: [labeled] - -jobs: - add_title_prefix: - name: "Issue/PR: add title prefix" - continue-on-error: true - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/github-script@v8 - name: "Issue/PR: update title" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let prefixLabels = { - "python": "Python", - "java": "Java", - ".NET": ".Net" - }; - - function addTitlePrefix(title, prefix) - { - // Update the title based on the label and prefix - // Check if the title starts with the prefix (case-sensitive) - if (!title.startsWith(prefix + ": ")) { - // If not, check if the first word is the label (case-insensitive) - if (title.match(new RegExp(`^${prefix}`, 'i'))) { - // If yes, replace it with the prefix (case-sensitive) - title = title.replace(new RegExp(`^${prefix}`, 'i'), prefix); - } else { - // If not, prepend the prefix to the title - title = prefix + ": " + title; - } - } - - return title; - } - - labelAdded = context.payload.label.name - - // Check if the issue or PR has the label - if (labelAdded in prefixLabels) { - let prefix = prefixLabels[labelAdded]; - switch(context.eventName) { - case 'issues': - github.rest.issues.update({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - title: addTitlePrefix(context.payload.issue.title, prefix) - }); - break - - case 'pull_request_target': - github.rest.pulls.update({ - pull_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - title: addTitlePrefix(context.payload.pull_request.title, prefix) - }); - break - default: - core.setFailed('Unrecognited eventName: ' + context.eventName); - } - } diff --git a/.github/workflows/markdown-link-check-config.json b/.github/workflows/markdown-link-check-config.json deleted file mode 100644 index 50ada4911..000000000 --- a/.github/workflows/markdown-link-check-config.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "/github/" - }, - { - "pattern": "./actions" - }, - { - "pattern": "./blob" - }, - { - "pattern": "./issues" - }, - { - "pattern": "./discussions" - }, - { - "pattern": "./pulls" - }, - { - "pattern": "^http://localhost" - }, - { - "pattern": "^https://localhost" - }, - { - "pattern": "^https://platform.openai.com" - }, - { - "pattern": "^https://outlook.office.com/bookings" - } - ], - "timeout": "20s", - "retryOn429": true, - "retryCount": 3, - "fallbackRetryDelay": "30s", - "aliveStatusCodes": [200, 206, 429, 500, 503] -} diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml deleted file mode 100644 index bc1a1fa72..000000000 --- a/.github/workflows/markdown-link-check.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Check .md links - -on: - workflow_dispatch: - pull_request: - branches: [ "main" ] - -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - # check out the latest version of the code - steps: - - uses: actions/checkout@v6 - - # Checks the status of hyperlinks in .md files in verbose mode - - name: Check links - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - use-verbose-mode: "yes" - config-file: ".github/workflows/markdown-link-check-config.json" diff --git a/.github/workflows/merge-gatekeeper.yml b/.github/workflows/merge-gatekeeper.yml deleted file mode 100644 index adb6811ab..000000000 --- a/.github/workflows/merge-gatekeeper.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Merge Gatekeeper - -on: - pull_request: - branches: [ "main", "feature*" ] - merge_group: - branches: ["main"] - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - merge-gatekeeper: - runs-on: ubuntu-latest - # Restrict permissions of the GITHUB_TOKEN. - # Docs: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs - permissions: - checks: read - statuses: read - steps: - - name: Run Merge Gatekeeper - # NOTE: v1 is updated to reflect the latest v1.x.y. Please use any tag/branch that suits your needs: - # https://github.com/upsidr/merge-gatekeeper/tags - # https://github.com/upsidr/merge-gatekeeper/branches - uses: upsidr/merge-gatekeeper@v1 - if: github.event_name == 'pull_request' - with: - token: ${{ secrets.GITHUB_TOKEN }} - timeout: 3600 diff --git a/.github/workflows/typos.yaml b/.github/workflows/typos.yaml deleted file mode 100644 index 532f4d5dc..000000000 --- a/.github/workflows/typos.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Check pull requests for typos. -# -# Configuration: .github/_typos.toml -# -# Info: https://github.com/marketplace/actions/typos-action -# Local install: brew install typos-cli -# Local install: conda install typos -# Local run: typos -c .github/_typos.toml - -name: Spell Check - -on: - workflow_dispatch: - pull_request: - branches: [ "main" ] - -jobs: - run: - name: Spell Check with Typos - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v6 - - - name: Use custom config file - uses: crate-ci/typos@master - with: - config: .github/_typos.toml - write_changes: false diff --git a/.github/workflows/update-version.sh b/.github/workflows/update-version.sh deleted file mode 100755 index 5db3622f6..000000000 --- a/.github/workflows/update-version.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/bash - -POSITIONAL_ARGS=() - -while [[ $# -gt 0 ]]; do - case $1 in - -f|--file) - file="$2" - shift # past argument - shift # past value - ;; - -p|--propsFile) - propsFile="$2" - shift # past argument - shift # past value - ;; - -b|--buildAndRevisionNumber) - buildAndRevisionNumber="$2" - shift # past argument - shift # past value - ;; - -*|--*) - echo "Unknown option $1" - exit 1 - ;; - *) - POSITIONAL_ARGS+=("$1") # save positional arg - shift # past argument - ;; - esac -done - -set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters - -if [ -z "$file" ]; then - echo "ERROR: Parameter file (-f|--file) not provided" - exit 1; -elif [ ! -f "$file" ]; then - echo "ERROR: file ${file} not found" - exit 1; -fi - -if [ -n "$(cat $file | grep -i "false")" ]; then - echo "Project is marked as NOT packable - skipping." - exit 0; -fi - -if [ -z "$propsFile" ]; then - echo "ERROR: Parameter propsFile (-f|--file) not provided" - exit 1; -elif [ ! -f "$propsFile" ]; then - echo "ERROR: propsFile ${file} not found" - exit 1; -fi - -if [ -z "$buildAndRevisionNumber" ]; then - echo "ERROR: Parameter buildAndRevisionNumber (-b|--buildAndRevisionNumber) not provided" - exit 1; -fi - -propsVersionString=$(cat $propsFile | grep -i ""); -regex="([0-9.]*)<\/Version>" -if [[ $propsVersionString =~ $regex ]]; then - propsVersion=${BASH_REMATCH[1]} -else - echo "ERROR: Version tag not found in propsFile" - exit 1; -fi - -if [ -z "$propsVersion" ]; then - echo "ERROR: Version tag not found in propsFile" - exit 1; -elif [[ ! "$propsVersion" =~ ^0.* ]]; then - echo "ERROR: Version expected to start with 0. Actual: ${propsVersion}" - exit 1; -fi - -fullVersionString="${propsVersion}.${buildAndRevisionNumber}-preview" - -if [[ ! "$fullVersionString" =~ ^0.* ]]; then - echo "ERROR: Version expected to start with 0. Actual: ${fullVersionString}" - exit 1; -fi - -echo "==== Project: ${file} ===="; -echo "propsFile = ${propsFile}" -echo "buildAndRevisionNumber = ${buildAndRevisionNumber}" -echo "version prefix from propsFile = ${propsVersion}" -echo "full version string: ${fullVersionString}" - -versionInProj=$(cat $file | grep -i ""); -if [ -n "$versionInProj" ]; then - # Version tag already exists in the csproj. Let's replace it. - echo "Updating version tag..." - content=$(cat $file | sed --expression="s/\([0-9]*.[0-9]*\)<\/Version>/$fullVersionString<\/Version>/g"); -else - # Version tag not found in the csproj. Let's add it. - echo "Project is packable - adding version tag..." - content=$(cat $file | sed --expression="s/<\/Project>/$fullVersionString<\/Version><\/PropertyGroup><\/Project>/g"); -fi - -if [ $? -ne 0 ]; then exit 1; fi -echo "$content" && echo "$content" > $file; -if [ $? -ne 0 ]; then exit 1; fi - -echo "DONE"; -echo ""; diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 44c24fc06..000000000 --- a/.gitignore +++ /dev/null @@ -1,64 +0,0 @@ -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -# JetBrains IntelliJ -.idea -*.ipr -*.iml -*.iws - -# Maven settings -conf.properties -java/**/target -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar - -# Eclipse m2e generated files -# Eclipse Core -.project -# JDT-specific (Eclipse Java Development Tools) -.classpath - -# Other -.env -certs/ -launchSettings.json -config.development.yaml -*.development.config -*.development.json -.DS_Store -node_modules/ -obj/ -bin/ -_dev/ -.dev/ -*.devis.* -.vs/ -*.user -**/.vscode/chrome -**/.vscode/.ropeproject/objectdb -*.pyc -.ipynb_checkpoints -.jython_cache/ -__pycache__/ -.mypy_cache/ -__pypackages__/ -.pdm.toml -global.json -.java-version diff --git a/.mvn/jvm.config b/.mvn/jvm.config deleted file mode 100644 index 32599cefe..000000000 --- a/.mvn/jvm.config +++ /dev/null @@ -1,10 +0,0 @@ ---add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED ---add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ---add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70b..000000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# 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. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index d24ed88a4..000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "ms-java.vscode-java-pack", - ] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index bd5534a58..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 6f3bd17c1..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "editor.formatOnType": true, - "editor.formatOnSave": true, - "editor.formatOnPaste": true, - "editor.bracketPairColorization.enabled": true, - "editor.guides.bracketPairs": "active", - "notebook.output.textLineLimit": 500, - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/Thumbs.db": true - }, - "[java]": { - "editor.formatOnSave": false, - "editor.tabSize": 4, - "editor.codeActionsOnSave": { - "source.fixAll": "never" - }, - }, - "java.debug.settings.onBuildFailureProceed": true, - "java.compile.nullAnalysis.mode": "disabled", - "java.configuration.updateBuildConfiguration": "interactive" -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index feea3bb00..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0.0", - "inputs": [ - { - "id": "filter", - "type": "promptString", - "default": "", - "description": "Enter a filter to pass as argument or filter" - } - ] -} diff --git a/BUILD.md b/BUILD.md deleted file mode 100644 index bc0c61ce5..000000000 --- a/BUILD.md +++ /dev/null @@ -1,117 +0,0 @@ -# Semantic Kernel for Java - -Semantic Kernel (SK) is a lightweight foundation that lets you easily mix conventional programming languages with the -latest in -Large Language Model (LLM) AI "prompts" with templating, chaining, and planning capabilities out-of-the-box. - -To learn more about Microsoft Semantic Kernel, visit -the [Microsoft Semantic Kernel documentation](https://learn.microsoft.com/en-us/semantic-kernel/whatissk). - -The Microsoft Semantic Kernel for Java is a library that implements the key concepts and foundations of Microsoft -Semantic Kernel. It is designed -to be used in Java applications in both client (desktop, mobile, CLIs) and server environments in an idiomatic way, and -to be easily integrated with other Java libraries -and frameworks. - -## Quickstart - -To get an idea of how to use the Semantic Kernel for Java, you can check -the [syntax-examples](samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples) folder for -examples of common AI-enabled scenarios. - -## Get started - -To run the LLM prompts and semantic functions in this kernel, make sure you have -an [Open AI API Key](https://platform.openai.com/) -or [Azure Open AI service key](https://learn.microsoft.com/azure/cognitive-services/openai/). - -### Requirements - -To build the Semantic Kernel for Java, you will need: - -- **Required**: - - [OpenJDK 17](https://microsoft.com/openjdk/) or newer - -### Build the Semantic Kernel - -1. Clone this repository - - git clone https://github.com/microsoft/semantic-kernel-java - -2. Build the project with the Maven Wrapper - - cd semantic-kernel - ./mvnw install - -3. (Optional) To run a FULL build including static analysis and end-to-end tests that might require a valid OpenAI key, - run the following command: - - ./mvnw clean install -Prelease,bug-check,with-samples - -## Using the Semantic Kernel for Java - -The library is organized in a set of dependencies published to Maven Central. For a list of the Maven dependencies and -how to use each of them, see [PACKAGES.md](PACKAGES.md). - -Alternatively, check the `samples` folder for examples of common AI-enabled scenarios implemented with Semantic Kernel -for Java. - -## Discord community - -Join the [Microsoft Semantic Kernel Discord community](https://aka.ms/java-sk-discord) to discuss the Semantic Kernel -and get help from the community. We have a `#java` channel for Java-specific questions. - -## Contributing - -### Testing locally - -The project may contain end-to-end tests that require an OpenAI key to run. To run these tests locally, you -will need to set the following environment variable: - -- `CLIENT_KEY` - the OpenAI API key. - -If you are using Azure OpenAI, you will also need to set the following environment variables: - -- `CLIENT_ENDPOINT` - the Azure OpenAI endpoint found in **Keys * Endpoint** section of the Azure OpenAI service. -- `AZURE_CLIENT_KEY` - the Azure OpenAI API key found in **Keys * Endpoint** section of the Azure OpenAI service. -- `MODEL_ID` - the custom name you chose for your deployment when you deployed a model. It can be - found under **Resource Management > Deployments** in the Azure Portal. - -For more information, see the Azure OpenAI documentation -on [how to get your Azure OpenAI credentials](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart?pivots=rest-api&tabs=command-line#retrieve-key-and-endpoint). - -To run the unit tests only, run the following command: - - ./mvnw package - -To run all tests, including integration tests that require an OpenAI key, run the following command: - - ./mvnw verify -Prelease,bug-check,with-samples - -### Submitting a pull request - -Before submitting a pull request, please make sure that you have run the project with the command: - -```shell -./mvnw clean package -Pbug-check -``` - -The bug-check profile will detect some static analysis issues that will prevent merging as well as apply formatting -requirements to the code base. - -Also ensure that: - -- All new code is covered by unit tests -- All new code is covered by integration tests - -Once your proposal is ready, submit a pull request. The pull request will be reviewed by the project maintainers. - -Make sure your pull request has an objective title and a clear description explaining the problem and solution. - -## License - -This project is licensed under the [MIT License](LICENSE). - -## Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 0267d08f7..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,135 +0,0 @@ -# 1.4.4-RC2 - -- Upgrade many dependencies to recent versions -- Migrate from "Tool calls" to "Function calls" terminology, deprecated OpenAIFunctionToolCall -- Refactored Data storage area to be more extensible and added Oracle Database support (Thank you to the contributors - from Oracle for the contribution) - -# 1.4.4-RC1 - -- Add Agent framework abstractions. -- Add ChatCompletionAgent implementation. -- Add FunctionChoiceBehavior for OpenAI, replacing the older ToolCallBehavior. - -# 1.4.3 - -- Bug fix for execution on Android (https://github.com/microsoft/semantic-kernel-java/pull/284) -- Upgrade to azure-ai-openai 1.0.0-beta.14 - -# 1.4.2 - -- Fix bug effecting using native Java methods with OpenAI tool calling - -# 1.4.1 - -- Add Otel Telemetry on function invocations -- Fix bug to add type information to OpenAI function parameters -- Improve efficiency of cosine similarity calculation -- Fix concurrency bugs on database creation -- Add sample demonstrating a text splitter for chunking text for embedding -- Add hybridSearchAsync support to Azure AI Search - -# 1.4.0 - -- Upgrade to azure-ai-openai 1.0.0-beta.12 -- Add vector stores with vector search support for Azure AI Search, Redis, JDBC with Postgres, MySQL, SQLite and HSQLDB. - Moving these features out of the experimental stage. - -# 1.3.0 - -- Added support for Json Schema to Open AI Chat Completions -- Upgraded to openai sdk 1.0.0-beta.11 -- Added convenience method `FunctionInvocation.withResultTypeAutoConversion` which sets the return type and registers a - type converter based on Jackson for the return type. -- Added localization support for error/debug messages -- Add vector search to experimental vector stores. - - Approximate vector search for Azure AI Search, Redis and JDBC with Postgres. - - Exhaustive vector search for VolatileVectorStore and default JDBC query provider, MySQL, SQLite and HSQLDB. - -### Bug Fixes - -- Fixed type converters not being passed on to be used in tool invocations - -### Breaking Changes - -- To support the new Json Schema feature, ResponseFormat has changed from an enum to a class. - -# 1.2.2 - -- Fix bug in `FunctionInvocation` not using per-invocation type conversion when calling `withResultType`. -- Fix bug in Global Hooks not being invoked under certain circumstances. -- Add fluent returns to `ChatHistory` `addXMessage` methods. -- Add user agent opt-out for OpenAI requests by setting the property `semantic-kernel.useragent-disable` to `true`. -- Add several convenience `invokePromptAsync` methods to `Kernel`. -- Allow Handlebars templates to call Javabean getters to extract data from invocation arguments. -- Improve thread safety of `ChatHistory`. - -#### Experimental Changes - -- Add JDBC vector store - -#### Non-API Changes - -- Add custom type Conversion example, `CustomTypes_Example` -- Dependency updates and pom cleanup -- Documentation updates - -# 1.2.0 - -- Add ability to use image_url as content for a OpenAi chat completion - - As part of this `ChatMessageTextContent` and `ChatMessageImageContent` was added that extends the - existing `ChatMessageContent` class. `ChatMessageContent` for now defaults to a text content type for backwards - compatibility. However, users are encouraged to migrate to using the builders on `ChatMessageTextContent` to - create text based chat messages. - - Constructors of `ChatMessageContent` were also modified to support this change. -- Added preliminary hugging face implementation that is still in development/beta. -- Added Gemini support -- Added OpenTelemetry spans for OpenAI requests -- Update the user agent for OpenAI requests -- Move XML parsing classes to implementation package as they are not expected to be used by users. - -#### Non-API Changes - -- Reorganized the repository when moving to the new Github location -- Removed non-Java files -- Update readmes -- Update build scripts -- Bring back Spring example project - -# 1.1.5 - -- Fix bug with removing new lines on function parameters on Windows -- Fix bug forming serializing arguments to tool calls - -# 1.1.3 - -- Fix bug appending plugin name to tool calls -- Improve exception handling in OpenAIChatCompletion - -# 1.1.2 - -- Upgrade azure-identity to 1.12.1 -- Remove fixed netty version in bom - -# 1.1.1 - -- Upgrade azure-ai-openai to 1.0.0-beta.8 - -# 1.1.0 - -### Breaking Changes - -- `ChatHistory` no longer has a default message, see below for more details. - -### Api Changes - -- Allow setting deployment name in addition to modelId on AI services. -- Remove default message of "Assistant is a large language model" from ChatHistory - - **This is a breaking change if you were relying on the default message in your code** -- Add InvocationReturnMode and rework OpenAi chat completion to allow configuring what data is returned from Chat - requests - -### Other - -- Reorganize example projects and documentation structure. -- Number of sample updates and bug fixes. \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index f9ba8cf65..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,9 +0,0 @@ -# Microsoft Open Source Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). - -Resources: - -- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) -- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/COMMUNITY.md b/COMMUNITY.md deleted file mode 100644 index 7afdb02cb..000000000 --- a/COMMUNITY.md +++ /dev/null @@ -1,16 +0,0 @@ -# Welcome to the Semantic Kernel Community! - -Below are some ways that you can get involved in the SK Community. - -## Engage on Github - -File issues, submit PRs, and provide feedback and ideas to what you'd like to see from the Semantic Kernel. -We do our best to respond to each submission. - -## Join the conversation on Discord - -We have a growing and active channel on Discord where you can get help, engage in lively discussion, -and share what you've built with Semantic Kernel! - -Join our Discord: -[https://aka.ms/SKDiscord](https://aka.ms/SKDiscord) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 14cbb9be6..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,147 +0,0 @@ -# Contributing to Semantic Kernel - -You can contribute to Semantic Kernel with issues and pull requests (PRs). Simply -filing issues for problems you encounter is a great way to contribute. Contributing -code is greatly appreciated. - -## Reporting Issues - -We always welcome bug reports, API proposals and overall feedback. Here are a few -tips on how you can make reporting your issue as effective as possible. - -### Where to Report - -New issues can be reported in our [list of issues](https://github.com/microsoft/semantic-kernel/issues). - -Before filing a new issue, please search the list of issues to make sure it does -not already exist. - -If you do find an existing issue for what you wanted to report, please include -your own feedback in the discussion. Do consider upvoting (👍 reaction) the original -post, as this helps us prioritize popular issues in our backlog. - -### Writing a Good Bug Report - -Good bug reports make it easier for maintainers to verify and root cause the -underlying problem. -The better a bug report, the faster the problem will be resolved. Ideally, a bug -report should contain the following information: - -- A high-level description of the problem. -- A _minimal reproduction_, i.e. the smallest size of code/configuration required - to reproduce the wrong behavior. -- A description of the _expected behavior_, contrasted with the _actual behavior_ observed. -- Information on the environment: OS/distribution, CPU architecture, SDK version, etc. -- Additional information, e.g. Is it a regression from previous versions? Are there - any known workarounds? - -## Contributing Changes - -Project maintainers will merge accepted code changes from contributors. - -### DOs and DON'Ts - -DO's: - -- **DO** follow the standard coding conventions - - - [.NET](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions) - - [Python](https://pypi.org/project/black/) - - [Typescript](https://typescript-eslint.io/rules/)/[React](https://github.com/jsx-eslint/eslint-plugin-react/tree/master/docs/rules) - -- **DO** give priority to the current style of the project or file you're changing - if it diverges from the general guidelines. -- **DO** include tests when adding new features. When fixing bugs, start with - adding a test that highlights how the current behavior is broken. -- **DO** keep the discussions focused. When a new or related topic comes up - it's often better to create new issue than to side track the discussion. -- **DO** clearly state on an issue that you are going to take on implementing it. -- **DO** blog and tweet (or whatever) about your contributions, frequently! - -DON'Ts: - -- **DON'T** surprise us with big pull requests. Instead, file an issue and start - a discussion so we can agree on a direction before you invest a large amount of time. -- **DON'T** commit code that you didn't write. If you find code that you think is a good - fit to add to Semantic Kernel, file an issue and start a discussion before proceeding. -- **DON'T** submit PRs that alter licensing related files or headers. If you believe - there's a problem with them, file an issue and we'll be happy to discuss it. -- **DON'T** make new APIs without filing an issue and discussing with us first. - -### Breaking Changes - -Contributions must maintain API signature and behavioral compatibility. Contributions -that include breaking changes will be rejected. Please file an issue to discuss -your idea or change if you believe that a breaking change is warranted. - -### Suggested Workflow - -We use and recommend the following workflow: - -1. Create an issue for your work. - - You can skip this step for trivial changes. - - Reuse an existing issue on the topic, if there is one. - - Get agreement from the team and the community that your proposed change is - a good one. - - Clearly state that you are going to take on implementing it, if that's the case. - You can request that the issue be assigned to you. Note: The issue filer and - the implementer don't have to be the same person. -2. Create a personal fork of the repository on GitHub (if you don't already have one). -3. In your fork, create a branch off of main (`git checkout -b mybranch`). - - Name the branch so that it clearly communicates your intentions, such as - "issue-123" or "githubhandle-issue". -4. Make and commit your changes to your branch. -5. Add new tests corresponding to your change, if applicable. -6. Run the relevant scripts in [the section below](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#dev-scripts) to ensure that your build is clean and all tests are passing. -7. Create a PR against the repository's **main** branch. - - State in the description what issue or improvement your change is addressing. - - Verify that all the Continuous Integration checks are passing. -8. Wait for feedback or approval of your changes from the code maintainers. -9. When area owners have signed off, and all checks are green, your PR will be merged. - -### Development scripts - -The scripts below are used to build, test, and lint within the project. - -- Python: see [python/DEV_SETUP.md](https://github.com/microsoft/semantic-kernel/blob/main/python/DEV_SETUP.md#pipeline-checks). -- .NET: - - Build/Test: `run build.cmd` or `bash build.sh` - - Linting (auto-fix): `dotnet format` -- Typescript: - - Build/Test: `yarn build` - - Linting (auto-fix): `yarn lint:fix` - -### Adding Plugins and Memory Connectors - -When considering contributions to plugins and memory connectors for Semantic -Kernel, please note the following guidelines: - -#### Plugins - -We appreciate your interest in extending Semantic Kernel's functionality through -plugins. However, we want to clarify our approach to hosting plugins within our -GitHub repository. To maintain a clean and manageable codebase, we will not be -hosting plugins directly in the Semantic Kernel GitHub repository. -Instead, we encourage contributors to host their plugin code in separate -repositories under their own GitHub accounts or organization. You can then -provide a link to your plugin repository in the relevant discussions, issues, -or documentation within the Semantic Kernel repository. This approach ensures -that each plugin can be maintained independently and allows for easier tracking -of updates and issues specific to each plugin. - -#### Memory Connectors - -For memory connectors, while we won't be directly adding hosting for them within -the Semantic Kernel repository, we highly recommend building memory connectors -as separate plugins. Memory connectors play a crucial role in interfacing with -external memory systems, and treating them as plugins enhances modularity and -maintainability. - -### PR - CI Process - -The continuous integration (CI) system will automatically perform the required -builds and run tests (including the ones you are expected to run) for PRs. Builds -and test runs must be clean. - -If the CI build fails for any reason, the PR issue will be updated with a link -that can be used to determine the cause of the failure. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9e841e7a2..000000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - MIT License - - Copyright (c) Microsoft Corporation. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE diff --git a/PACKAGES.md b/PACKAGES.md deleted file mode 100644 index a6e2dc7a4..000000000 --- a/PACKAGES.md +++ /dev/null @@ -1,76 +0,0 @@ -# Semantic Kernel for Java Packages - -The Semantic Kernel has the packages below, all are under the groupId `com.microsoft.semantic-kernel`, and can be imported -to maven. - -```xml - - com.microsoft.semantic-kernel - semantickernel-api - -``` - -A BOM is provided that can be used to define the versions of all Semantic Kernel packages. - -```xml - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${semantickernel.version} - import - pom - - - -``` - -## Common Packages - -`semantickernel-bom` -: A Maven project BOM that can be used to define the versions of all Semantic Kernel packages. - -`semantickernel-api` -: Package that defines the core public API for the Semantic Kernel for a Maven project. - -## Services - -`semantickernel-aiservices-openai` -: Provides a connector that can be used to interact with the OpenAI API. - -## Example Configurations - -### Example: OpenAI + SQLite - -POM XML for a simple project that uses OpenAI. - -```xml - - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${semantickernel.version} - import - pom - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-connectors-ai-openai - - - -``` - - - diff --git a/README.md b/README.md deleted file mode 100644 index 27585762d..000000000 --- a/README.md +++ /dev/null @@ -1,75 +0,0 @@ -[![Builds](https://github.com/microsoft/semantic-kernel-java/actions/workflows/java-build.yml/badge.svg?branch=main)](https://github.com/microsoft/semantic-kernel-java/actions/workflows/java-build.yml) -[![License: MIT](https://img.shields.io/github/license/microsoft/semantic-kernel)](https://github.com/microsoft/semantic-kernel-java/blob/main/LICENSE) -[![Discord](https://img.shields.io/discord/1063152441819942922?label=Discord&logo=discord&logoColor=white&color=d82679)](https://aka.ms/SKDiscord) - -# Semantic Kernel for Java - -Welcome to the Semantic Kernel for Java. For detailed documentation, visit [Microsoft Learn](https://learn.microsoft.com/en-us/semantic-kernel/overview/?tabs=Java&pivots=programming-language-java). - -[Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/) is an SDK that integrates Large Language Models (LLMs) like [OpenAI](https://platform.openai.com/docs/introduction), [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service), and [Hugging Face](https://huggingface.co/) -with conventional programming languages like C#, Python, and Java. Semantic Kernel achieves this by allowing you to define [plugins](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/plugins??tabs=Java&pivots=programming-language-java) that can be chained together in just a [few lines of code](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/chaining-functions?tabs=Java&pivots=programming-language-java#using-the-runasync-method-to-simplify-your-code). - -What makes Semantic Kernel _special_, however, is its ability to _automatically_ orchestrate plugins with AI. With Semantic Kernel [planners](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/planner?tabs=Java&pivots=programming-language-java), you can ask an LLM to generate a plan that achieves a user's unique goal. Afterwards, Semantic Kernel will execute the plan for the user. - -For C#, Python and other language support, see [microsoft/semantic-kernel](https://github.com/microsoft/semantic-kernel). - -#### Please star the repo to show your support for this project! - -![Orchestrating plugins with planner](https://learn.microsoft.com/en-us/semantic-kernel/media/kernel-infographic.png) - -## Getting started with Semantic Kernel for Java - -The quickest way to get started with the basics is to get an API key from either OpenAI or Azure OpenAI and to run one of the Java console applications/scripts below. - -1. Clone the repository: `git clone https://github.com/microsoft/semantic-kernel-java.git` -2. Follow the instructions [Start learning how to use Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/get-started/quick-start-guide?tabs=Java&pivots=programming-language-java). - -## Documentation: Learning how to use Semantic Kernel - -The fastest way to learn how to use Semantic Kernel is with our walkthroughs -on our Learn site. - -1. 📖 [Overview of the kernel](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/?tabs=Java&pivots=programming-language-java) -1. 🔌 [Understanding AI plugins](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/plugins?tabs=Java&pivots=programming-language-java) -1. 👄 [Creating semantic functions](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/semantic-functions?tabs=Java&pivots=programming-language-java) -1. 💽 [Creating native functions](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/native-functions?tabs=Java&pivots=programming-language-java) -1. ⛓️ [Chaining functions together](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/chaining-functions?tabs=Java&pivots=programming-language-java) -1. 🤖 [Auto create plans with planner](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/planner?tabs=Java&pivots=programming-language-java) -1. 💡 [Create and run a ChatGPT plugin](https://learn.microsoft.com/en-us/semantic-kernel/ai-orchestration/chatgpt-plugins?tabs=Java&pivots=programming-language-java) - -## Join the community - -We welcome your contributions and suggestions to SK community! One of the easiest -ways to participate is to engage in discussions in the GitHub repository. -Bug reports and fixes are welcome! - -For new features, components, or extensions, please open an issue and discuss with -us before sending a PR. This is to avoid rejection as we might be taking the core -in a different direction, but also to consider the impact on the larger ecosystem. - -To learn more and get started: - -- Read the [documentation](https://learn.microsoft.com/en-us/semantic-kernel/overview/?tabs=Java&pivots=programming-language-java) -- Learn how to [contribute](https://learn.microsoft.com/en-us/semantic-kernel/support/contributing?tabs=Java&pivots=programming-language-java) to the project -- Join the [Discord community](https://aka.ms/SKDiscord) -- Attend [regular office hours and SK community events](COMMUNITY.md) -- Follow the team on our [blog](https://aka.ms/sk/blog) - -## Contributor Wall of Fame - -[![semantic-kernel contributors](https://contrib.rocks/image?repo=microsoft/semantic-kernel-java)](https://github.com/microsoft/semantic-kernel-java/graphs/contributors) - -## Code of Conduct - -This project has adopted the -[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the -[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) -with any additional questions or comments. - -## License - -Copyright (c) Microsoft Corporation. All rights reserved. - -Licensed under the [MIT](LICENSE) license. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index eed215e18..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). - -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://www.microsoft.com/en-us/msrc/definition-of-a-security-vulnerability?rtc=1), please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** - -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). - -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc?rtc=2). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/en-us/msrc?rtc=2). - -Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://www.microsoft.com/en-us/msrc/bounty?rtc=2) page for more details about our active programs. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd?rtc=2). - - diff --git a/agents/semantickernel-agents-core/pom.xml b/agents/semantickernel-agents-core/pom.xml deleted file mode 100644 index 1270d00d0..000000000 --- a/agents/semantickernel-agents-core/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-agents-core - - Semantic Kernel Chat Completion Agent - Chat Completion Agent for Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - - \ No newline at end of file diff --git a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java deleted file mode 100644 index b5294fe6b..000000000 --- a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatCompletionAgent.java +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents.chatcompletion; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.agents.AgentInvokeOptions; -import com.microsoft.semantickernel.agents.AgentResponseItem; -import com.microsoft.semantickernel.agents.AgentThread; -import com.microsoft.semantickernel.agents.KernelAgent; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.functionchoice.AutoFunctionChoiceBehavior; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory; -import com.microsoft.semantickernel.services.ServiceNotFoundException; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.stream.Collectors; - -public class ChatCompletionAgent extends KernelAgent { - - private ChatCompletionAgent( - String id, - String name, - String description, - Kernel kernel, - KernelArguments kernelArguments, - InvocationContext context, - String instructions, - PromptTemplate template) { - super( - id, - name, - description, - kernel, - kernelArguments, - context, - instructions, - template); - } - - /** - * Invoke the agent with the given chat history. - * - * @param messages The chat history to process - * @param thread The agent thread to use - * @param options The options for invoking the agent - * @return A Mono containing the agent response - */ - @Override - public Mono>>> invokeAsync( - List> messages, - @Nullable AgentThread thread, - @Nullable AgentInvokeOptions options) { - return ensureThreadExistsWithMessagesAsync(messages, thread, ChatHistoryAgentThread::new) - .cast(ChatHistoryAgentThread.class) - .flatMap(agentThread -> { - // Extract the chat history from the thread - ChatHistory history = new ChatHistory( - agentThread.getChatHistory().getMessages()); - - // Invoke the agent with the chat history - return internalInvokeAsync( - history, - agentThread, - options) - .map(chatMessageContents -> chatMessageContents.stream() - .map(message -> new AgentResponseItem>(message, - agentThread)) - .collect(Collectors.toList())); - }); - } - - private Mono>> internalInvokeAsync( - ChatHistory history, - AgentThread thread, - @Nullable AgentInvokeOptions options) { - if (options == null) { - options = new AgentInvokeOptions(); - } - - final Kernel kernel = options.getKernel() != null ? options.getKernel() : this.kernel; - final KernelArguments arguments = mergeArguments(options.getKernelArguments()); - final String additionalInstructions = options.getAdditionalInstructions(); - final InvocationContext invocationContext = options.getInvocationContext() != null - ? options.getInvocationContext() - : this.invocationContext; - - try { - ChatCompletionService chatCompletionService = kernel - .getService(ChatCompletionService.class, arguments); - - PromptExecutionSettings executionSettings = invocationContext != null - && invocationContext.getPromptExecutionSettings() != null - ? invocationContext.getPromptExecutionSettings() - : arguments.getExecutionSettings() - .get(chatCompletionService.getServiceId()); - - // Build base invocation context - InvocationContext.Builder builder = InvocationContext.builder() - .withPromptExecutionSettings(executionSettings) - .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY); - - if (invocationContext != null) { - builder = builder - .withTelemetry(invocationContext.getTelemetry()) - .withFunctionChoiceBehavior(invocationContext.getFunctionChoiceBehavior()) - .withToolCallBehavior(invocationContext.getToolCallBehavior()) - .withContextVariableConverter(invocationContext.getContextVariableTypes()) - .withKernelHooks(invocationContext.getKernelHooks()); - } - - InvocationContext agentInvocationContext = builder.build(); - - return renderInstructionsAsync(kernel, arguments, agentInvocationContext).flatMap( - instructions -> { - // Create a new chat history with the instructions - ChatHistory chat = new ChatHistory( - instructions); - - // Add agent additional instructions - if (additionalInstructions != null) { - chat.addMessage(new ChatMessageContent<>( - AuthorRole.SYSTEM, - additionalInstructions)); - } - - // Add the chat history to the new chat - chat.addAll(history); - - // Retrieve the chat message contents asynchronously and notify the thread - if (shouldNotifyFunctionCalls(agentInvocationContext)) { - // Notify all messages including function calls - return chatCompletionService - .getChatMessageContentsAsync(chat, kernel, agentInvocationContext) - .flatMapMany(Flux::fromIterable) - .concatMap(message -> notifyThreadOfNewMessageAsync(thread, message) - .thenReturn(message)) - // Filter out function calls and their results - .filter(message -> message.getContent() != null - && message.getAuthorRole() != AuthorRole.TOOL) - .collect(Collectors.toList()); - } - - // Return chat completion messages without notifying the thread - // We shouldn't add the function call content to the thread, since - // we don't know if the user will execute the call. They should add it themselves. - return chatCompletionService.getChatMessageContentsAsync(chat, kernel, - agentInvocationContext); - }); - - } catch (ServiceNotFoundException e) { - return Mono.error(e); - } - } - - boolean shouldNotifyFunctionCalls(InvocationContext invocationContext) { - if (invocationContext == null) { - return false; - } - - if (invocationContext.getFunctionChoiceBehavior() != null && invocationContext - .getFunctionChoiceBehavior() instanceof AutoFunctionChoiceBehavior) { - return ((AutoFunctionChoiceBehavior) invocationContext.getFunctionChoiceBehavior()) - .isAutoInvoke(); - } - - if (invocationContext.getToolCallBehavior() != null) { - return invocationContext.getToolCallBehavior().isAutoInvokeAllowed(); - } - - return false; - } - - @Override - public Mono notifyThreadOfNewMessageAsync(AgentThread thread, - ChatMessageContent message) { - return Mono.defer(() -> { - return thread.onNewMessageAsync(message); - }); - } - - /** - * Builder for creating instances of ChatCompletionAgent. - */ - public static Builder builder() { - return new Builder(); - } - - public static class Builder implements SemanticKernelBuilder { - private String id; - private String name; - private String description; - private Kernel kernel; - private KernelArguments kernelArguments; - private InvocationContext invocationContext; - private String instructions; - private PromptTemplate template; - - /** - * Set the ID of the agent. - * - * @param id The ID of the agent. - */ - public Builder withId(String id) { - this.id = id; - return this; - } - - /** - * Set the name of the agent. - * - * @param name The name of the agent. - */ - public Builder withName(String name) { - this.name = name; - return this; - } - - /** - * Set the description of the agent. - * - * @param description The description of the agent. - */ - public Builder withDescription(String description) { - this.description = description; - return this; - } - - /** - * Set the kernel to use for the agent. - * - * @param kernel The kernel to use. - */ - public Builder withKernel(Kernel kernel) { - this.kernel = kernel; - return this; - } - - /** - * Set the kernel arguments to use for the agent. - * - * @param KernelArguments The kernel arguments to use. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withKernelArguments(KernelArguments KernelArguments) { - this.kernelArguments = KernelArguments; - return this; - } - - /** - * Set the instructions for the agent. - * - * @param instructions The instructions for the agent. - */ - public Builder withInstructions(String instructions) { - this.instructions = instructions; - return this; - } - - /** - * Set the invocation context for the agent. - * - * @param invocationContext The invocation context to use. - */ - public Builder withInvocationContext(InvocationContext invocationContext) { - this.invocationContext = invocationContext; - return this; - } - - /** - * Set the template for the agent. - * - * @param template The template to use. - */ - public Builder withTemplate(PromptTemplate template) { - this.template = template; - return this; - } - - /** - * Build the ChatCompletionAgent instance. - * - * @return The ChatCompletionAgent instance. - */ - public ChatCompletionAgent build() { - return new ChatCompletionAgent( - id, - name, - description, - kernel, - kernelArguments, - invocationContext, - instructions, - template); - } - - /** - * Build the ChatCompletionAgent instance with the given prompt template config and factory. - * - * @param promptTemplateConfig The prompt template config to use. - * @param promptTemplateFactory The prompt template factory to use. - * @return The ChatCompletionAgent instance. - */ - public ChatCompletionAgent build(PromptTemplateConfig promptTemplateConfig, - PromptTemplateFactory promptTemplateFactory) { - return new ChatCompletionAgent( - id, - name, - description, - kernel, - kernelArguments, - invocationContext, - promptTemplateConfig.getTemplate(), - promptTemplateFactory.tryCreate(promptTemplateConfig)); - } - } -} diff --git a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java b/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java deleted file mode 100644 index 6b3f62a9b..000000000 --- a/agents/semantickernel-agents-core/src/main/java/com/microsoft/semantickernel/agents/chatcompletion/ChatHistoryAgentThread.java +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents.chatcompletion; - -import com.microsoft.semantickernel.agents.AgentThread; -import com.microsoft.semantickernel.agents.BaseAgentThread; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import reactor.core.publisher.Mono; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.List; -import java.util.UUID; - -public class ChatHistoryAgentThread extends BaseAgentThread { - private ChatHistory chatHistory; - - /** - * Constructor for ChatHistoryAgentThread. - * - */ - public ChatHistoryAgentThread() { - this(UUID.randomUUID().toString(), new ChatHistory()); - } - - /** - * Constructor for ChatHistoryAgentThread. - * - * @param chatHistory The chat history. - */ - public ChatHistoryAgentThread(@Nullable ChatHistory chatHistory) { - this(UUID.randomUUID().toString(), chatHistory); - } - - /** - * Constructor for ChatHistoryAgentThread. - * - * @param id The ID of the thread. - * @param chatHistory The chat history. - */ - public ChatHistoryAgentThread(String id, @Nullable ChatHistory chatHistory) { - super(id); - this.chatHistory = chatHistory != null ? chatHistory : new ChatHistory(); - } - - /** - * Get the chat history. - * - * @return The chat history. - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public ChatHistory getChatHistory() { - return chatHistory; - } - - @Override - public Mono createAsync() { - if (this.id == null) { - this.id = UUID.randomUUID().toString(); - chatHistory = new ChatHistory(); - } - return Mono.just(id); - } - - @Override - public Mono deleteAsync() { - return Mono.fromRunnable(chatHistory::clear); - } - - /** - * Create a copy of the thread. - * - * @return A new instance of the thread. - */ - @Override - public ChatHistoryAgentThread copy() { - return new ChatHistoryAgentThread(this.id, new ChatHistory(chatHistory.getMessages())); - } - - @Override - public Mono onNewMessageAsync(ChatMessageContent newMessage) { - return Mono.fromRunnable(() -> { - chatHistory.addMessage(newMessage); - }); - } - - public List> getMessages() { - return chatHistory.getMessages(); - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder implements SemanticKernelBuilder { - private String id; - private ChatHistory chatHistory; - - /** - * Set the ID of the thread. - * - * @param id The ID of the thread. - * @return The builder instance. - */ - public Builder withId(String id) { - this.id = id; - return this; - } - - /** - * Set the chat history. - * - * @param chatHistory The chat history. - * @return The builder instance. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withChatHistory(ChatHistory chatHistory) { - this.chatHistory = chatHistory; - return this; - } - - @Override - public ChatHistoryAgentThread build() { - return new ChatHistoryAgentThread(id, chatHistory); - } - } -} diff --git a/aiservices/google/pom.xml b/aiservices/google/pom.xml deleted file mode 100644 index 145ee5494..000000000 --- a/aiservices/google/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-aiservices-google - Semantic Kernel Google Services - Google services for Semantic Kernel - - - - - com.google.cloud - libraries-bom - 26.49.0 - pom - import - - - - - - - com.google.cloud - google-cloud-vertexai - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-localization - - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - - - javax.xml.stream - stax-api - provided - - - - \ No newline at end of file diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiService.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiService.java deleted file mode 100644 index a65e96afb..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiService.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google; - -import com.google.cloud.vertexai.VertexAI; -import com.microsoft.semantickernel.services.AIService; - -import javax.annotation.Nullable; - -/** - * Makes a Gemini service available to the Semantic Kernel. - */ -public class GeminiService implements AIService { - private final VertexAI client; - private final String modelId; - - /** - * Creates a new Gemini service. - * @param client The VertexAI client - * @param modelId The Gemini model ID - */ - protected GeminiService(VertexAI client, String modelId) { - this.client = client; - this.modelId = modelId; - } - - @Nullable - @Override - public String getModelId() { - return modelId; - } - - @Nullable - @Override - public String getServiceId() { - return null; - } - - /** - * Gets the VertexAI client. - * @return The VertexAI client - */ - protected VertexAI getClient() { - return client; - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiServiceBuilder.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiServiceBuilder.java deleted file mode 100644 index 3312299cc..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/GeminiServiceBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google; - -import com.google.cloud.vertexai.VertexAI; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import javax.annotation.Nullable; - -/** - * Builder for a Gemini service. - * @param The type of the service - * @param The type of the builder - */ -public abstract class GeminiServiceBuilder> implements - SemanticKernelBuilder { - - @Nullable - protected String modelId; - @Nullable - protected VertexAI client; - - /** - * Sets the model ID for the service - * - * @param modelId The model ID - * @return The builder - */ - public U withModelId(String modelId) { - this.modelId = modelId; - return (U) this; - } - - /** - * Sets the VertexAI client for the service - * - * @param client The VertexAI client - * @return The builder - */ - public U withVertexAIClient(VertexAI client) { - this.client = client; - return (U) this; - } - - @Override - public abstract T build(); -} \ No newline at end of file diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatCompletion.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatCompletion.java deleted file mode 100644 index 2bd45c022..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatCompletion.java +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -import com.google.cloud.vertexai.VertexAI; -import com.google.cloud.vertexai.api.Content; -import com.google.cloud.vertexai.api.FunctionDeclaration; -import com.google.cloud.vertexai.api.FunctionResponse; -import com.google.cloud.vertexai.api.GenerateContentResponse; -import com.google.cloud.vertexai.api.GenerationConfig; -import com.google.cloud.vertexai.api.Part; -import com.google.cloud.vertexai.api.Schema; -import com.google.cloud.vertexai.api.Tool; -import com.google.cloud.vertexai.api.Type; -import com.google.cloud.vertexai.generativeai.GenerativeModel; -import com.google.protobuf.Struct; -import com.google.protobuf.Value; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.google.GeminiService; -import com.microsoft.semantickernel.aiservices.google.GeminiServiceBuilder; -import com.microsoft.semantickernel.aiservices.google.implementation.MonoConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.exceptions.SKCheckedException; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import com.microsoft.semantickernel.services.chatcompletion.StreamingChatContent; -import java.io.IOException; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * A chat completion service that uses the Gemini model to generate chat completions. - */ -public class GeminiChatCompletion extends GeminiService implements ChatCompletionService { - - private static final Logger LOGGER = LoggerFactory.getLogger(GeminiChatCompletion.class); - - /** - * Constructor for {@link GeminiChatCompletion}. - * @param client The VertexAI client - * @param modelId The model ID - */ - public GeminiChatCompletion(VertexAI client, String modelId) { - super(client, modelId); - } - - /** - * Create a new instance of {@link GeminiChatCompletion.Builder}. - * - * @return a new instance of {@link GeminiChatCompletion.Builder} - */ - public static Builder builder() { - return new Builder(); - } - - @Override - public Mono>> getChatMessageContentsAsync(String prompt, - @Nullable Kernel kernel, @Nullable InvocationContext invocationContext) { - GeminiXMLPromptParser.GeminiParsedPrompt parsedPrompt = GeminiXMLPromptParser.parse(prompt); - - return this.getChatMessageContentsAsync(parsedPrompt.getChatHistory(), kernel, - invocationContext); - } - - @Override - public Flux> getStreamingChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - - LOGGER.warn("Streaming has been called on GeminiChatCompletion service. " - + "This is currently not supported in Gemini. " - + "The results will be returned in a non streaming fashion."); - - return getChatMessageContentsAsync(chatHistory, kernel, invocationContext) - .flatMapIterable(chatMessageContents -> chatMessageContents) - .map(content -> { - return new GeminiStreamingChatMessageContent( - content.getAuthorRole(), - content.getContent(), - getModelId(), - content.getInnerContent(), - content.getEncoding(), - content.getMetadata(), - null, - UUID.randomUUID().toString()); - }); - } - - @Override - public Flux> getStreamingChatMessageContentsAsync(String prompt, - @Nullable Kernel kernel, @Nullable InvocationContext invocationContext) { - LOGGER.warn("Streaming has been called on GeminiChatCompletion service. " - + "This is currently not supported in Gemini. " - + "The results will be returned in a non streaming fashion."); - - return getChatMessageContentsAsync(prompt, kernel, invocationContext) - .flatMapIterable(chatMessageContents -> chatMessageContents) - .map(content -> { - return new GeminiStreamingChatMessageContent( - content.getAuthorRole(), - content.getContent(), - getModelId(), - content.getInnerContent(), - content.getEncoding(), - content.getMetadata(), - null, - UUID.randomUUID().toString()); - }); - } - - @Override - public Mono>> getChatMessageContentsAsync(ChatHistory chatHistory, - @Nullable Kernel kernel, @Nullable InvocationContext invocationContext) { - return internalChatMessageContentsAsync( - new ChatHistory(chatHistory.getMessages()), - new ChatHistory(), - kernel, - invocationContext, - Math.min(MAXIMUM_INFLIGHT_AUTO_INVOKES, - invocationContext != null && invocationContext.getToolCallBehavior() != null - ? invocationContext.getToolCallBehavior().getMaximumAutoInvokeAttempts() - : 0)); - } - - private Mono>> internalChatMessageContentsAsync( - ChatHistory fullHistory, ChatHistory newHistory, @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext, int invocationAttempts) { - - List contents = getContents(fullHistory); - - try { - GenerativeModel model = getGenerativeModel(kernel, invocationContext); - return MonoConverter.fromApiFuture(model.generateContentAsync(contents)) - .doOnError(e -> LOGGER.error( - SemanticKernelResources.getString("error.generating.chat.completion"), e)) - .flatMap(result -> { - // Get ChatMessageContent from the response - GeminiChatMessageContent response = getGeminiChatMessageContentFromResponse( - result); - - // Add assistant response to the chat history - fullHistory.addMessage(response); - newHistory.addMessage(response); - - // Just return the result: - // If we don't want to attempt to invoke any functions or if we have no function calls - if (invocationAttempts <= 0 || response.getGeminiFunctionCalls().isEmpty()) { - if (invocationContext != null && invocationContext - .returnMode() == InvocationReturnMode.FULL_HISTORY) { - return Mono.just(fullHistory.getMessages()); - } - if (invocationContext != null && invocationContext - .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { - ChatHistory lastMessage = new ChatHistory(); - lastMessage.addMessage(response); - - return Mono.just(lastMessage.getMessages()); - } - - return Mono.just(newHistory.getMessages()); - } - - // Perform the function calls - List> functionResults = response - .getGeminiFunctionCalls().stream() - .map(geminiFunctionCall -> performFunctionCall(kernel, invocationContext, - geminiFunctionCall)) - .collect(Collectors.toList()); - - Mono> combinedResults = Flux - .fromIterable(functionResults) - .flatMap(mono -> mono) - .collectList(); - - // Add the function responses to the chat history - return combinedResults.flatMap(results -> { - ChatMessageContent functionResponsesMessage = new GeminiChatMessageContent<>( - AuthorRole.USER, - "", null, null, null, null, results); - - fullHistory.addMessage(functionResponsesMessage); - newHistory.addMessage(functionResponsesMessage); - - return internalChatMessageContentsAsync(fullHistory, newHistory, kernel, - invocationContext, invocationAttempts - 1); - }); - }); - } catch (SKCheckedException | IOException e) { - return Mono.error(new SKException("Error generating chat completion", e)); - } - } - - // Convert from ChatHistory to List - private List getContents(ChatHistory chatHistory) { - List contents = new ArrayList<>(); - chatHistory.forEach(chatMessageContent -> { - Content.Builder contentBuilder = Content.newBuilder(); - - if (chatMessageContent.getAuthorRole() == AuthorRole.USER) { - contentBuilder.setRole(GeminiRole.USER.toString()); - - if (chatMessageContent instanceof GeminiChatMessageContent) { - GeminiChatMessageContent message = (GeminiChatMessageContent) chatMessageContent; - - message.getGeminiFunctionCalls().forEach(geminiFunction -> { - FunctionResult functionResult = geminiFunction.getFunctionResult(); - if (functionResult == null || functionResult.getResult() == null) { - throw new SKException("Gemini failed to return a result"); - } - - FunctionResponse functionResponse = FunctionResponse.newBuilder() - .setName(geminiFunction.getFunctionCall().getName()) - .setResponse(Struct.newBuilder().putFields("result", - Value.newBuilder() - .setStringValue( - (String) functionResult.getResult()) - .build())) - .build(); - - contentBuilder - .addParts(Part.newBuilder().setFunctionResponse(functionResponse)); - }); - } - } else if (chatMessageContent.getAuthorRole() == AuthorRole.ASSISTANT) { - contentBuilder.setRole(GeminiRole.MODEL.toString()); - - if (chatMessageContent instanceof GeminiChatMessageContent) { - GeminiChatMessageContent message = (GeminiChatMessageContent) chatMessageContent; - - message.getGeminiFunctionCalls().forEach(geminiFunctionCall -> { - contentBuilder.addParts(Part.newBuilder() - .setFunctionCall(geminiFunctionCall.getFunctionCall())); - }); - } - } - - if (chatMessageContent.getContent() != null - && !chatMessageContent.getContent().isEmpty()) { - contentBuilder.addParts(Part.newBuilder().setText(chatMessageContent.getContent())); - } - - contents.add(contentBuilder.build()); - }); - - return contents; - } - - private GeminiChatMessageContent getGeminiChatMessageContentFromResponse( - GenerateContentResponse response) { - StringBuilder message = new StringBuilder(); - List functionCalls = new ArrayList<>(); - - response.getCandidatesList().forEach( - candidate -> { - Content content = candidate.getContent(); - if (content.getPartsCount() == 0) { - return; - } - - content.getPartsList().forEach(part -> { - if (!part.getFunctionCall().getName().isEmpty()) { - // We only care about the function call here - // Execution of the function call will be done later - functionCalls.add(new GeminiFunctionCall(part.getFunctionCall(), null)); - } - if (!part.getText().isEmpty()) { - message.append(part.getText()); - } - }); - }); - - FunctionResultMetadata metadata = FunctionResultMetadata - .build(UUID.randomUUID().toString(), response.getUsageMetadata(), OffsetDateTime.now()); - - return new GeminiChatMessageContent<>(AuthorRole.ASSISTANT, - message.toString(), null, null, null, metadata, functionCalls); - } - - private GenerativeModel getGenerativeModel(@Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) throws SKCheckedException { - GenerativeModel.Builder modelBuilder = new GenerativeModel.Builder() - .setModelName(getModelId()) - .setVertexAi(getClient()); - - if (invocationContext != null) { - if (invocationContext.getPromptExecutionSettings() != null) { - PromptExecutionSettings settings = invocationContext.getPromptExecutionSettings(); - - if (settings.getResultsPerPrompt() < 1 - || settings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) { - throw SKCheckedException.build( - SemanticKernelResources.getString("error.building.generative.model"), - new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format( - "Results per prompt must be in range between 1 and %d, inclusive.", - MAX_RESULTS_PER_PROMPT))); - } - - GenerationConfig config = GenerationConfig.newBuilder() - .setMaxOutputTokens(settings.getMaxTokens()) - .setTemperature((float) settings.getTemperature()) - .setTopP((float) settings.getTopP()) - .setCandidateCount(settings.getResultsPerPrompt()) - .build(); - - modelBuilder.setGenerationConfig(config); - } - - if (invocationContext.getToolCallBehavior() != null && kernel != null) { - List tools = new ArrayList<>(); - Tool tool = getTool(kernel, invocationContext.getToolCallBehavior()); - if (tool != null) { - tools.add(tool); - } - modelBuilder.setTools(tools); - } - } - - return modelBuilder.build(); - } - - private FunctionDeclaration buildFunctionDeclaration(KernelFunction function) { - FunctionDeclaration.Builder functionBuilder = FunctionDeclaration.newBuilder(); - functionBuilder.setName( - ToolCallBehavior.formFullFunctionName(function.getPluginName(), function.getName())); - functionBuilder.setDescription(function.getDescription()); - - List parameters = function.getMetadata().getParameters(); - if (parameters != null && !parameters.isEmpty()) { - Schema.Builder parametersBuilder = Schema.newBuilder(); - - function.getMetadata().getParameters().forEach(parameter -> { - parametersBuilder.setType(Type.OBJECT); - parametersBuilder.putProperties( - parameter.getName(), - Schema.newBuilder().setType(Type.STRING) - .setDescription(parameter.getDescription()).build()); - }); - - functionBuilder.setParameters(parametersBuilder.build()); - } - - return functionBuilder.build(); - } - - @Nullable - private Tool getTool(@Nullable Kernel kernel, @Nullable ToolCallBehavior toolCallBehavior) { - if (kernel == null || toolCallBehavior == null) { - return null; - } - - Tool.Builder toolBuilder = Tool.newBuilder(); - - // If a specific function is required to be called - if (toolCallBehavior instanceof ToolCallBehavior.RequiredKernelFunction) { - KernelFunction kernelFunction = ((ToolCallBehavior.RequiredKernelFunction) toolCallBehavior) - .getRequiredFunction(); - - toolBuilder.addFunctionDeclarations(buildFunctionDeclaration(kernelFunction)); - } - // If a set of functions are enabled to be called - if (toolCallBehavior instanceof ToolCallBehavior.AllowedKernelFunctions) { - ToolCallBehavior.AllowedKernelFunctions enabledKernelFunctions = (ToolCallBehavior.AllowedKernelFunctions) toolCallBehavior; - - kernel.getPlugins() - .forEach(plugin -> plugin.getFunctions().forEach((name, function) -> { - // check if all kernel functions are enabled or if the specific function is enabled - if (enabledKernelFunctions.isAllKernelFunctionsAllowed() || - enabledKernelFunctions.isFunctionAllowed(function.getPluginName(), - function.getName())) { - toolBuilder.addFunctionDeclarations(buildFunctionDeclaration(function)); - } - })); - } - - return toolBuilder.build(); - } - - /** - * Invoke the Gemini function call. - * @param kernel The semantic kernel - * @param invocationContext Additional context for the invocation - * @param geminiFunction The Gemini function call - * @return The result of the function call - */ - public Mono performFunctionCall(@Nullable Kernel kernel, - @Nullable InvocationContext invocationContext, GeminiFunctionCall geminiFunction) { - if (kernel == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "Kernel must be provided to perform function call"); - } - - String[] name = geminiFunction.getFunctionCall().getName() - .split(ToolCallBehavior.FUNCTION_NAME_SEPARATOR); - - String pluginName = name[0]; - String functionName = name[1]; - - KernelPlugin plugin = kernel.getPlugin(pluginName); - if (plugin == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format("Plugin %s not found in kernel", pluginName)); - } - KernelFunction function = plugin.get(functionName); - - if (function == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format("Kernel function %s not found in plugin %s", functionName, - pluginName)); - } - - ContextVariableTypes contextVariableTypes = invocationContext == null - ? new ContextVariableTypes() - : invocationContext.getContextVariableTypes(); - - KernelArguments.Builder arguments = KernelArguments.builder(); - geminiFunction.getFunctionCall().getArgs().getFieldsMap().forEach((key, value) -> { - arguments.withVariable(key, value.getStringValue()); - }); - - return function - .invokeAsync(kernel) - .withArguments(arguments.build()) - .withResultType(contextVariableTypes.getVariableTypeForClass(String.class)) - .map(result -> new GeminiFunctionCall(geminiFunction.getFunctionCall(), result)); - } - - /** - * Builder for {@link GeminiChatCompletion}. - */ - public static class Builder extends GeminiServiceBuilder { - - @Override - public GeminiChatCompletion build() { - if (this.client == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "VertexAI client must be provided"); - } - - if (this.modelId == null || modelId.isEmpty()) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "Gemini model id must be provided"); - } - - return new GeminiChatCompletion(client, modelId); - } - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatMessageContent.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatMessageContent.java deleted file mode 100644 index 28cae4fb5..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiChatMessageContent.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -import com.google.cloud.vertexai.api.FunctionCall; -import com.google.cloud.vertexai.api.FunctionResponse; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Represents the content of a chat message. - * - * @param The type of the inner content. - */ -public class GeminiChatMessageContent extends ChatMessageContent { - @Nonnull - private final List geminiFunctionCalls; - - /** - * Creates a new instance of the {@link GeminiChatMessageContent} class. - * - * @param authorRole The author role that generated the content. - * @param content The content. - * @param modelId The model id. - * @param innerContent The inner content. - * @param encoding The encoding. - * @param metadata The metadata. - * @param geminiFunctionCalls The function calls. - */ - public GeminiChatMessageContent( - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable T innerContent, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata, - @Nullable List geminiFunctionCalls) { - super(authorRole, content, modelId, innerContent, encoding, metadata); - if (geminiFunctionCalls == null) { - this.geminiFunctionCalls = Collections.emptyList(); - } else { - this.geminiFunctionCalls = Collections.unmodifiableList(geminiFunctionCalls); - } - } - - /** - * Gets the function calls. - * - * @return The function calls. - */ - @Nonnull - public List getGeminiFunctionCalls() { - return Collections.unmodifiableList(geminiFunctionCalls); - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiFunctionCall.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiFunctionCall.java deleted file mode 100644 index 0a6e87d4e..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiFunctionCall.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -import com.google.cloud.vertexai.api.FunctionCall; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents a function call in Gemini. - */ -public class GeminiFunctionCall { - @Nonnull - private final FunctionCall functionCall; - @Nullable - private final FunctionResult functionResult; - private final String pluginName; - private final String functionName; - - /** - * Creates a new Gemini function call. - * @param functionCall The function call - * @param functionResult The result of the function invocation - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public GeminiFunctionCall( - @Nonnull FunctionCall functionCall, - @Nullable FunctionResult functionResult) { - this.functionCall = functionCall; - this.functionResult = functionResult; - - String[] name = functionCall.getName().split(ToolCallBehavior.FUNCTION_NAME_SEPARATOR); - this.pluginName = name[0]; - this.functionName = name[1]; - } - - /** - * Gets the plugin name. - * @return The plugin name - */ - public String getPluginName() { - return pluginName; - } - - /** - * Gets the function name. - * @return The function name - */ - public String getFunctionName() { - return functionName; - } - - /** - * Gets the function call. - * @return The function call - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public FunctionCall getFunctionCall() { - return functionCall; - } - - /** - * Gets the function result. - * @return The function result - */ - @Nullable - public FunctionResult getFunctionResult() { - return functionResult; - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiRole.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiRole.java deleted file mode 100644 index 03983553b..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiRole.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -/** - * Represents the role of a message in a Gemini conversation. - */ -public enum GeminiRole { - /** - * A user message is a message generated by the user. - */ - USER("user"), - /** - * A model message is a message generated by the model. - */ - MODEL("model"); - - private final String role; - - private GeminiRole(String role) { - this.role = role; - } - - @Override - public String toString() { - return role; - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiStreamingChatMessageContent.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiStreamingChatMessageContent.java deleted file mode 100644 index e6f0d5511..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiStreamingChatMessageContent.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.StreamingChatContent; -import java.nio.charset.Charset; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Represents the content of a chat message. - * - * @param The type of the inner content. - */ -public class GeminiStreamingChatMessageContent extends GeminiChatMessageContent implements - StreamingChatContent { - - private final String id; - - /** - * Creates a new instance of the {@link GeminiChatMessageContent} class. - * - * @param authorRole The author role that generated the content. - * @param content The content. - * @param modelId The model id. - * @param innerContent The inner content. - * @param encoding The encoding. - * @param metadata The metadata. - * @param id The id of the message. - * @param geminiFunctionCalls The function calls. - */ - public GeminiStreamingChatMessageContent(AuthorRole authorRole, String content, - @Nullable String modelId, @Nullable T innerContent, @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata, - @Nullable List geminiFunctionCalls, - String id) { - super(authorRole, content, modelId, innerContent, encoding, metadata, geminiFunctionCalls); - this.id = id; - } - - @Override - public String getId() { - return id; - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiXMLPromptParser.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiXMLPromptParser.java deleted file mode 100644 index e43032dc1..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/chatcompletion/GeminiXMLPromptParser.java +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.chatcompletion; - -import com.azure.core.util.BinaryData; -import com.google.cloud.vertexai.api.FunctionDeclaration; -import com.google.cloud.vertexai.api.Schema; -import com.microsoft.semantickernel.implementation.chatcompletion.ChatPromptParseVisitor; -import com.microsoft.semantickernel.implementation.chatcompletion.ChatXMLPromptParser; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Parses an XML prompt for a Gemini chat. - */ -public class GeminiXMLPromptParser { - - private static final Logger LOGGER = LoggerFactory.getLogger(GeminiXMLPromptParser.class); - - /** - * Represents a parsed prompt for Gemini chat. - */ - public static class GeminiParsedPrompt { - - private final ChatHistory chatHistory; - private final List functions; - - /** - * Creates a new parsed prompt. - * @param parsedChatHistory The chat history - * @param parsedFunctions The functions declarations. - */ - protected GeminiParsedPrompt( - ChatHistory parsedChatHistory, - @Nullable List parsedFunctions) { - this.chatHistory = parsedChatHistory; - if (parsedFunctions == null) { - parsedFunctions = new ArrayList<>(); - } - this.functions = parsedFunctions; - } - - /** - * Gets the chat history. - * @return A copy of the chat history. - */ - public ChatHistory getChatHistory() { - return new ChatHistory(chatHistory.getMessages()); - } - - /** - * Gets the functions declarations. - * @return A copy of the functions declarations. - */ - public List getFunctions() { - return Collections.unmodifiableList(functions); - } - } - - private static AuthorRole getAuthorRole(String role) { - switch (role) { - case "user": - return AuthorRole.USER; - case "assistant": - return AuthorRole.ASSISTANT; - case "system": - return AuthorRole.SYSTEM; - case "tool": - return AuthorRole.TOOL; - default: - LOGGER.error("Unknown role: " + role); - return AuthorRole.USER; - } - } - - private static class GeminiChatPromptParseVisitor - implements ChatPromptParseVisitor { - - @Nullable - private GeminiParsedPrompt parsedRaw = null; - private final List functionDefinitions = new ArrayList<>(); - private final ChatHistory chatHistory = new ChatHistory(); - - @Override - public ChatPromptParseVisitor addMessage( - String role, - String content) { - chatHistory.addMessage( - ChatMessageTextContent.builder() - .withContent(content) - .withAuthorRole(getAuthorRole(role)) - .build()); - return this; - } - - @Override - public ChatPromptParseVisitor addFunction( - String name, - @Nullable String description, - @Nullable BinaryData parameters) { - - // TODO: Build the parameters schema - Schema.Builder parametersBuilder = Schema.newBuilder(); - - FunctionDeclaration.Builder function = FunctionDeclaration.newBuilder() - .setName(name) - .setDescription(description) - .setParameters(parametersBuilder.build()); - - functionDefinitions.add(function.build()); - return this; - } - - @Override - public boolean areMessagesEmpty() { - return chatHistory.getMessages().isEmpty(); - } - - @Override - public ChatPromptParseVisitor fromRawPrompt( - String rawPrompt) { - - ChatMessageContent message = ChatMessageTextContent.userMessage(rawPrompt); - - this.parsedRaw = new GeminiParsedPrompt( - new ChatHistory(Collections.singletonList(message)), null); - - return this; - } - - @Override - public GeminiParsedPrompt get() { - if (parsedRaw != null) { - return parsedRaw; - } - - return new GeminiParsedPrompt(chatHistory, functionDefinitions); - } - - @Override - public ChatPromptParseVisitor reset() { - return new GeminiChatPromptParseVisitor(); - } - } - - /** - * Create a GeminiParsedPrompt by parsing a raw prompt. - * @param rawPrompt the raw prompt to parse. - * @return The parsed prompt. - */ - public static GeminiParsedPrompt parse(String rawPrompt) { - ChatPromptParseVisitor visitor = ChatXMLPromptParser.parse( - rawPrompt, - new GeminiChatPromptParseVisitor()); - - return visitor.get(); - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/implementation/MonoConverter.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/implementation/MonoConverter.java deleted file mode 100644 index 3209a03c8..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/implementation/MonoConverter.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.implementation; - -import com.google.api.core.ApiFuture; -import reactor.core.publisher.Mono; - -public class MonoConverter { - public static Mono fromApiFuture(ApiFuture apiFuture) { - return Mono.create(sink -> { - apiFuture.addListener(() -> { - try { - T result = apiFuture.get(); - sink.success(result); - } catch (Exception e) { - sink.error(e); - } - }, runnable -> new Thread(runnable).start()); - }); - } -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiStreamingTextContent.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiStreamingTextContent.java deleted file mode 100644 index 9bf9a6fd3..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiStreamingTextContent.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.textcompletion; - -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.textcompletion.TextContent; -import javax.annotation.Nullable; - -/** - * StreamingTextContent is a wrapper for TextContent that allows for streaming. - */ -public class GeminiStreamingTextContent extends StreamingTextContent { - - /** - * Initializes a new instance of the {@code StreamingTextContent} class with a provided text - * content. - * - * @param content The text content. - */ - public GeminiStreamingTextContent(TextContent content) { - super(content, 0, null, null); - } - - @Override - @Nullable - public String getContent() { - TextContent content = getInnerContent(); - if (content == null) { - return null; - } - return content.getContent(); - } - -} diff --git a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiTextGenerationService.java b/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiTextGenerationService.java deleted file mode 100644 index 5e5551161..000000000 --- a/aiservices/google/src/main/java/com/microsoft/semantickernel/aiservices/google/textcompletion/GeminiTextGenerationService.java +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.google.textcompletion; - -import com.google.cloud.vertexai.VertexAI; -import com.google.cloud.vertexai.api.GenerateContentResponse; -import com.google.cloud.vertexai.api.GenerationConfig; -import com.google.cloud.vertexai.generativeai.GenerativeModel; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.google.GeminiService; -import com.microsoft.semantickernel.aiservices.google.GeminiServiceBuilder; -import com.microsoft.semantickernel.aiservices.google.implementation.MonoConverter; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.exceptions.SKCheckedException; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.textcompletion.TextContent; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.io.IOException; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * A Gemini service for text generation. - * @see TextGenerationService - */ -public class GeminiTextGenerationService extends GeminiService implements TextGenerationService { - - private static final Logger LOGGER = LoggerFactory.getLogger(GeminiTextGenerationService.class); - - /** - * Creates a new Gemini text generation service. - * @param client The VertexAI client - * @param modelId The Gemini model ID - */ - public GeminiTextGenerationService(VertexAI client, String modelId) { - super(client, modelId); - } - - /** - * Creates a new builder for a Gemini text generation service. - * @return The builder - */ - public static Builder builder() { - return new Builder(); - } - - @Override - public Mono> getTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel) { - return this.internalGetTextAsync(prompt, executionSettings); - } - - @Override - public Flux getStreamingTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel) { - return this - .internalGetTextAsync(prompt, executionSettings) - .flatMapMany(it -> Flux.fromStream(it.stream()) - .map(GeminiStreamingTextContent::new)); - } - - private Mono> internalGetTextAsync(String prompt, - @Nullable PromptExecutionSettings executionSettings) { - - try { - GenerativeModel model = getGenerativeModel(executionSettings); - return MonoConverter.fromApiFuture(model.generateContentAsync(prompt)) - .doOnError(e -> LOGGER.error("Error generating text", e)) - .flatMap(result -> { - List textContents = new ArrayList<>(); - - FunctionResultMetadata metadata = FunctionResultMetadata - .build( - UUID.randomUUID().toString(), - result.getUsageMetadata(), - OffsetDateTime.now()); - - result.getCandidatesList().forEach( - candidate -> { - candidate.getContent().getPartsList().forEach(part -> { - if (!part.getText().isEmpty()) { - textContents.add( - new TextContent(part.getText(), getModelId(), metadata)); - } - }); - }); - - return Mono.just(textContents); - }); - } catch (SKCheckedException | IOException e) { - return Mono.error(new SKException("Error generating text", e)); - } - } - - private GenerativeModel getGenerativeModel( - @Nullable PromptExecutionSettings executionSettings) throws SKCheckedException { - GenerativeModel.Builder modelBuilder = new GenerativeModel.Builder() - .setModelName(getModelId()) - .setVertexAi(getClient()); - - if (executionSettings != null) { - if (executionSettings.getResultsPerPrompt() < 1 - || executionSettings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) { - throw SKCheckedException.build("Error building generative model.", - new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format( - "Results per prompt must be in range between 1 and %d, inclusive.", - MAX_RESULTS_PER_PROMPT))); - } - - GenerationConfig config = GenerationConfig.newBuilder() - .setMaxOutputTokens(executionSettings.getMaxTokens()) - .setTemperature((float) executionSettings.getTemperature()) - .setTopP((float) executionSettings.getTopP()) - .setCandidateCount(executionSettings.getResultsPerPrompt()) - .build(); - - modelBuilder.setGenerationConfig(config); - } - - return modelBuilder.build(); - } - - /** - * Builder for a Gemini text generation service. - */ - public static class Builder extends - GeminiServiceBuilder { - - @Override - public GeminiTextGenerationService build() { - if (this.client == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "VertexAI client must be provided"); - } - - if (this.modelId == null || modelId.isEmpty()) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "Gemini model id must be provided"); - } - - return new GeminiTextGenerationService(client, modelId); - } - } -} diff --git a/aiservices/huggingface/pom.xml b/aiservices/huggingface/pom.xml deleted file mode 100644 index 152aba546..000000000 --- a/aiservices/huggingface/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - 4.0.0 - - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-aiservices-huggingface - Semantic Kernel Huggingface Services - Huggingface services for Semantic Kernel - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.azure - azure-core - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - - - javax.xml.stream - stax-api - provided - - - - - - - src/main/resources - true - - - - - diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/HuggingFaceClient.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/HuggingFaceClient.java deleted file mode 100644 index 4e8f9bb4d..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/HuggingFaceClient.java +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface; - -import com.azure.core.credential.KeyCredential; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.HttpMethod; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.HttpResponse; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.aiservices.huggingface.models.GeneratedTextItem; -import com.microsoft.semantickernel.aiservices.huggingface.models.TextGenerationRequest; -import com.microsoft.semantickernel.exceptions.SKException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import reactor.core.publisher.Mono; -import javax.annotation.Nullable; - -/** - * A client for the Hugging Face API. - */ -public class HuggingFaceClient { - - private final KeyCredential key; - private final String endpoint; - private final HttpClient httpClient; - - /** - * Creates a new Hugging Face client. - * @param key The key credential for endpoint authentication. - * @param endpoint The endpoint for the Hugging Face API. - * @param httpClient The HTTP client to use for requests. - */ - public HuggingFaceClient( - KeyCredential key, - String endpoint, - HttpClient httpClient) { - this.key = key; - this.endpoint = endpoint; - this.httpClient = httpClient; - } - - /* - * TODO: TGI - * public Mono getChatMessageContentsAsync( - * String modelId, - * ChatCompletionRequest chatCompletionRequest - * ) { - * try { - * String body = new ObjectMapper().writeValueAsString(chatCompletionRequest); - * return performRequest(modelId, body) - * .handle((response, sink) -> { - * ObjectMapper mapper = new ObjectMapper(); - * JavaType type = mapper.getTypeFactory(). - * constructCollectionType(List.class, GeneratedTextItem.class); - * try { - * sink.next(mapper.readValue(response, type)); - * } catch (JsonProcessingException e) { - * sink.error( - * new SKException("Failed to deserialize response from Hugging Face", - * e)); - * } - * }); - * } catch (JsonProcessingException e) { - * return Mono.error(new SKException("Failed to serialize request body", e)); - * } - * } - * - */ - - private static class GeneratedTextItemList { - - private final List> generatedTextItems; - - @JsonCreator - public GeneratedTextItemList( - List> generatedTextItems) { - this.generatedTextItems = generatedTextItems; - } - - } - - /** - * Gets the text contents from the Hugging Face API. - * @param modelId The model ID. - * @param textGenerationRequest The text generation request. - * @return The generated text items. - */ - public Mono> getTextContentsAsync( - String modelId, - TextGenerationRequest textGenerationRequest) { - try { - String body = new ObjectMapper().writeValueAsString(textGenerationRequest); - return performRequest(modelId, body) - .handle((response, sink) -> { - try { - ObjectMapper mapper = new ObjectMapper(); - JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, - GeneratedTextItemList.class); - GeneratedTextItemList data = mapper.readValue(response, - GeneratedTextItemList.class); - sink.next(data.generatedTextItems.get(0)); - } catch (Exception e) { - sink.error( - new SKException("Failed to deserialize response from Hugging Face", - e)); - } - }); - } catch (JsonProcessingException e) { - return Mono.error(new SKException("Failed to serialize request body", e)); - } - } - - private Mono performRequest(String modelId, - String body) { - HttpRequest request = new HttpRequest(HttpMethod.POST, endpoint) - .setHeader(HttpHeaderName.AUTHORIZATION, "Bearer " + key.getKey()) - .setHeader(HttpHeaderName.CONTENT_TYPE, "application/json") - .setHeader(HttpHeaderName.fromString("azureml-model-deployment"), modelId); - - request.setBody(body.getBytes(StandardCharsets.UTF_8)); - - Mono responseBody = httpClient - .send(request) - .onErrorResume( - e -> { - return Mono.error( - new SKException("Failed to send request to Hugging Face", e)); - }) - .flatMap(httpResponse -> { - if (httpResponse.getStatusCode() >= 400) { - return httpResponse.getBodyAsString() - .flatMap(errorBody -> { - return Mono.error(new SKException( - "Failed to get text content from Hugging Face. Status code: " - + httpResponse.getStatusCode() + " " + errorBody)); - }); - } else { - return Mono.just(httpResponse); - } - }) - .flatMap(HttpResponse::getBodyAsString); - return responseBody; - } - - /** - * Creates a new builder for a Hugging Face client. - * @return The builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for a Hugging Face client. - */ - public static class Builder { - - @Nullable - private KeyCredential key = null; - @Nullable - private String endpoint = null; - @Nullable - private HttpClient httpClient = null; - - /** - * Builds the Hugging Face client. - * @return The client - */ - public HuggingFaceClient build() { - if (httpClient == null) { - httpClient = HttpClient.createDefault(); - } - if (key == null) { - throw new SKException("Key credential is required"); - } - if (endpoint == null) { - throw new SKException("Endpoint is required"); - } - return new HuggingFaceClient( - key, - endpoint, - httpClient); - } - - /** - * Sets the key credential for the client. - * @param key The key credential - * @return The builder - */ - public Builder credential(KeyCredential key) { - this.key = key; - return this; - } - - /** - * Sets the endpoint for the client. - * @param endpoint The endpoint - * @return The builder - */ - public Builder endpoint(String endpoint) { - this.endpoint = endpoint; - return this; - } - - /** - * Sets the HTTP client for the client. - * @param httpClient The HTTP client - * @return The builder - */ - public Builder httpClient(HttpClient httpClient) { - this.httpClient = httpClient; - return this; - } - } -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/GeneratedTextItem.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/GeneratedTextItem.java deleted file mode 100644 index 12ed5be60..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/GeneratedTextItem.java +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Represents a generated text item deserialized from a JSON response. - */ -public class GeneratedTextItem { - - @Nullable - @JsonProperty("generated_text") - private final String generatedText; - - @Nullable - @JsonProperty("details") - private final TextGenerationDetails details; - - /** - * Constructor used by Jackson to deserialize a generated text item. - * @param generatedText The generated text. - * @param details The details of the generation. - */ - @JsonCreator - public GeneratedTextItem( - @JsonProperty("generated_text") @Nullable String generatedText, - @JsonProperty("details") @Nullable TextGenerationDetails details) { - this.generatedText = generatedText; - this.details = details; - } - - /** - * Gets the generated text. - * @return The generated text. - */ - @Nullable - public String getGeneratedText() { - return generatedText; - } - - /** - * Gets the details of the generation. - * @return The details of the generation. - */ - @Nullable - public TextGenerationDetails getDetails() { - return details; - } - - /** - * Represents the details of a text generation deserialized from a JSON response. - */ - public static class TextGenerationDetails { - - @Nullable - @JsonProperty("finish_reason") - private final String finishReason; - - @JsonProperty("generated_tokens") - private final int generatedTokens; - - @Nullable - @JsonProperty("seed") - private final Long seed; - - @Nullable - @JsonProperty("prefill") - private final List prefill; - - @Nullable - @JsonProperty("tokens") - private final List tokens; - - /** - * Constructor used by Jackson to deserialize text generation details. - * @param finishReason The reason the generation finished. - * @param generatedTokens The number of tokens generated. - * @param seed The seed used for generation. - * @param prefill The prefill tokens. - * @param tokens The generated tokens. - */ - @JsonCreator - public TextGenerationDetails( - @JsonProperty("finish_reason") @Nullable String finishReason, - @JsonProperty("generated_tokens") int generatedTokens, - @JsonProperty("seed") @Nullable Long seed, - @JsonProperty("prefill") @Nullable List prefill, - @JsonProperty("tokens") @Nullable List tokens) { - this.finishReason = finishReason; - this.generatedTokens = generatedTokens; - this.seed = seed; - if (prefill != null) { - this.prefill = new ArrayList<>(prefill); - } else { - this.prefill = null; - } - if (tokens != null) { - this.tokens = new ArrayList<>(tokens); - } else { - this.tokens = null; - } - } - - /** - * Gets the reason the generation finished. - * @return The reason the generation finished. - */ - @Nullable - public String getFinishReason() { - return finishReason; - } - - /** - * Gets the number of tokens generated. - * @return The number of tokens generated. - */ - public int getGeneratedTokens() { - return generatedTokens; - } - - /** - * Gets the seed used for generation. - * @return The seed used for generation. - */ - @Nullable - public Long getSeed() { - return seed; - } - - /** - * Gets the prefill tokens. - * @return The prefill tokens. - */ - @Nullable - public List getPrefill() { - return Collections.unmodifiableList(prefill); - } - - /** - * Gets the generated tokens. - * @return The generated tokens. - */ - @Nullable - public List getTokens() { - return Collections.unmodifiableList(tokens); - } - } - - /** - * Represents a prefill token deserialized from a JSON response. - */ - public static class TextGenerationPrefillToken { - - @JsonProperty("id") - private final int id; - - @Nullable - @JsonProperty("text") - private final String text; - - @JsonProperty("logprob") - private final double logProb; - - /** - * Constructor used by Jackson to deserialize a prefill token. - * @param id The token ID. - * @param text The token text. - * @param logProb The log probability of the token. - */ - @JsonCreator - public TextGenerationPrefillToken( - @JsonProperty("id") int id, - @JsonProperty("text") @Nullable String text, - @JsonProperty("logprob") double logProb) { - this.id = id; - this.text = text; - this.logProb = logProb; - } - - /** - * Gets the token ID. - * @return The token ID. - */ - public int getId() { - return id; - } - - /** - * Gets the token text. - * @return The token text. - */ - @Nullable - public String getText() { - return text; - } - - /** - * Gets the log probability of the token. - * @return The log probability of the token. - */ - public double getLogProb() { - return logProb; - } - } - - /** - * Represents a generated token deserialized from a JSON response. - */ - public static class TextGenerationToken extends TextGenerationPrefillToken { - - @JsonProperty("special") - private final boolean special; - - /** - * Constructor used by Jackson to deserialize a generated token. - * @param special Whether the token is special. - * @param id The token ID. - * @param text The token text. - * @param logProb The log probability of the token. - */ - @JsonCreator - public TextGenerationToken( - @JsonProperty("special") boolean special, - @JsonProperty("id") int id, - @JsonProperty("text") @Nullable String text, - @JsonProperty("logprob") double logProb) { - super(id, text, logProb); - this.special = special; - } - - /** - * Gets whether the token is special. - * @return Whether the token is special. - */ - public boolean isSpecial() { - return special; - } - } -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/TextGenerationRequest.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/TextGenerationRequest.java deleted file mode 100644 index 0e52b5681..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/TextGenerationRequest.java +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface.models; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.aiservices.huggingface.services.HuggingFacePromptExecutionSettings; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.List; - -/** - * Represents a request to generate text using the Hugging Face API. - */ -@JsonInclude(Include.NON_NULL) -public class TextGenerationRequest { - - /// - /// The input string to generate text for. - /// - @Nullable - @JsonProperty("inputs") - private final List inputs; - - /// - /// Enable streaming - /// - @JsonProperty("stream") - private final boolean stream; - - /// - /// Parameters used by the model for generation. - /// - - @Nullable - @JsonProperty("parameters") - private final HuggingFaceTextParameters parameters; - - /// - /// Options used by the model for generation. - /// - @Nullable - @JsonProperty("options") - private final HuggingFaceTextOptions options; - - /** - * Create a new instance of TextGenerationRequest. - * @param inputs The input string to generate text for. - * @param stream Enable streaming. - * @param parameters Parameters used by the model for generation. - * @param options Options used by the model for generation. - */ - public TextGenerationRequest( - @Nullable String inputs, - boolean stream, - @Nullable HuggingFaceTextParameters parameters, - @Nullable HuggingFaceTextOptions options) { - this.inputs = Arrays.asList(inputs); - this.stream = stream; - this.parameters = parameters; - this.options = options; - } - - /** - * Create a new instance of TextGenerationRequest. - * @param prompt The prompt to generate text for. - * @param executionSettings The settings for executing the prompt. - * @return A new instance of TextGenerationRequest. - */ - public static TextGenerationRequest fromPromptAndExecutionSettings(String prompt, - HuggingFacePromptExecutionSettings executionSettings) { - return new TextGenerationRequest( - prompt, - false, - new HuggingFaceTextParameters( - executionSettings.getTopK(), - executionSettings.getTopP(), - executionSettings.getTemperature(), - executionSettings.getRepetitionPenalty(), - executionSettings.getMaxTokens(), - executionSettings.getMaxTime(), - true, - null, - null, - executionSettings.getDetails()), - new HuggingFaceTextOptions()); - } - - /** - * Parameters used by the model for generation. - */ - public static class HuggingFaceTextParameters { - - /// - /// (Default: None). Number to define the top tokens considered within the sample operation to create new text. - /// - @Nullable - @JsonProperty("top_k") - private final Integer topK; - - /// - /// (Default: None). Define the tokens that are within the sample operation of text generation. - /// Add tokens in the sample for more probable to least probable until the sum of the probabilities - /// is greater than top_p. - /// - @Nullable - @JsonProperty("top_p") - private final Double topP; - - /// - /// (Default: 1.0). Range (0.0-100.0). The temperature of the sampling operation. - /// 1 means regular sampling, 0 means always take the highest score, - /// 100.0 is getting closer to uniform probability. - /// - @Nullable - @JsonProperty("temperature") - private final Double temperature; - - /// - /// (Default: None). (0.0-100.0). The more a token is used within generation - /// the more it is penalized to not be picked in successive generation passes. - /// - @Nullable - @JsonProperty("repetition_penalty") - private final Double repetitionPenalty; - - /// - /// (Default: None). Range (0-250). The amount of new tokens to be generated, - /// this does not include the input length it is a estimate of the size of generated text you want. - /// Each new tokens slows down the request, so look for balance between response times - /// and length of text generated. - /// - @Nullable - @JsonProperty("max_new_tokens") - private final Integer maxNewTokens; - - /// - /// (Default: None). Range (0-120.0). The amount of time in seconds that the query should take maximum. - /// Network can cause some overhead so it will be a soft limit. - /// Use that in combination with max_new_tokens for best results. - /// - @Nullable - @JsonProperty("max_time") - private final Double maxTime; - - /// - /// (Default: True). If set to False, the return results will not contain the original query making it easier for prompting. - /// - @JsonProperty("return_full_text") - private final boolean returnFullText; - - /// - /// (Default: 1). The number of proposition you want to be returned. - /// - @Nullable - @JsonProperty("num_return_sequences") - private final Integer numReturnSequences; - - /// - /// (Optional: True). Whether or not to use sampling, use greedy decoding otherwise. - /// - @Nullable - @JsonProperty("do_sample") - private final Boolean doSample; - - /// - /// (Optional: True) Whether or not to include the details of the generation. - /// - /// - /// Disabling this won't provide information about token usage. - /// - @Nullable - @JsonProperty("details") - private final Boolean details; - - /** - * Creator method for jackson deserialization. - * @param topK The number of top tokens considered within the sample operation to create new text. - * @param topP The tokens that are within the sample operation of text generation. - * @param temperature The temperature of the sampling operation. - * @param repetitionPenalty The repetition penalty. - * @param maxNewTokens The amount of new tokens to be generated. - * @param maxTime The amount of time in seconds that the query should take maximum. - * @param returnFullText A value indicating whether the return results will contain the original query. - * @param numReturnSequences The number of propositions to be returned. - * @param doSample A value indicating whether to use sampling. - * @param details A value indicating whether to include the details of the generation. - */ - public HuggingFaceTextParameters( - @JsonProperty("top_k") @Nullable Integer topK, - @JsonProperty("top_p") @Nullable Double topP, - @JsonProperty("temperature") @Nullable Double temperature, - @JsonProperty("repetition_penalty") @Nullable Double repetitionPenalty, - @JsonProperty("max_new_tokens") @Nullable Integer maxNewTokens, - @JsonProperty("max_time") @Nullable Double maxTime, - @JsonProperty("return_full_text") boolean returnFullText, - @JsonProperty("num_return_sequences") @Nullable Integer numReturnSequences, - @JsonProperty("do_sample") @Nullable Boolean doSample, - @JsonProperty("details") @Nullable Boolean details) { - this.topK = topK; - this.topP = topP; - this.temperature = temperature; - this.repetitionPenalty = repetitionPenalty; - this.maxNewTokens = maxNewTokens; - this.maxTime = maxTime; - this.returnFullText = returnFullText; - this.numReturnSequences = numReturnSequences; - this.doSample = doSample; - this.details = details; - } - - /** - * Gets the number of top tokens considered within the sample operation to create new text. - * @return The number of top tokens considered within the sample operation to create new text. - */ - @Nullable - public Integer getTopK() { - return topK; - } - - /** - * Gets the tokens that are within the sample operation of text generation. - * @return The tokens that are within the sample operation of text generation. - */ - @Nullable - public Double getTopP() { - return topP; - } - - /** - * Gets the temperature of the sampling operation. - * @return The temperature of the sampling operation. - */ - @Nullable - public Double getTemperature() { - return temperature; - } - - /** - * Gets the repetition penalty. - * @return The repetition penalty. - */ - @Nullable - public Double getRepetitionPenalty() { - return repetitionPenalty; - } - - /** - * Gets the amount of new tokens to be generated. - * @return The amount of new tokens to be generated. - */ - @Nullable - public Integer getMaxNewTokens() { - return maxNewTokens; - } - - /** - * Gets the amount of time in seconds that the query should take maximum. - * @return The amount of time in seconds that the query should take maximum. - */ - @Nullable - public Double getMaxTime() { - return maxTime; - } - - /** - * Gets a value indicating whether the return results will contain the original query. - * @return A value indicating whether the return results will contain the original query. - */ - public boolean isReturnFullText() { - return returnFullText; - } - - /** - * Gets the number of propositions to be returned. - * @return The number of propositions to be returned. - */ - @Nullable - public Integer getNumReturnSequences() { - return numReturnSequences; - } - - /** - * Gets a value indicating whether to use sampling. - * @return A value indicating whether to use sampling. - */ - @Nullable - public Boolean getDoSample() { - return doSample; - } - - /** - * Gets a value indicating whether to include the details of the generation. - * @return A value indicating whether to include the details of the generation. - */ - @Nullable - public Boolean getDetails() { - return details; - } - } - - /** - * Options used by the model for generation. - */ - @SuppressFBWarnings("SS_SHOULD_BE_STATIC") - public static class HuggingFaceTextOptions { - - /// - /// (Default: true). There is a cache layer on the inference API to speedup requests we have already seen. - /// Most models can use those results as is as models are deterministic (meaning the results will be the same anyway). - /// However if you use a non deterministic model, you can set this parameter to prevent the caching mechanism from being - /// used resulting in a real new query. - /// - @JsonProperty("use_cache") - private final boolean useCache = true; - - /// - /// (Default: false) If the model is not ready, wait for it instead of receiving 503. - /// It limits the number of requests required to get your inference done. - /// It is advised to only set this flag to true after receiving a 503 error as it will limit hanging in your application to known places. - /// - @JsonProperty("wait_for_model") - private final boolean waitForModel = false; - - /** - * Gets a value indicating whether to use the cache layer on the inference API. - * @return A value indicating whether to use the cache layer on the inference API. - */ - public boolean isUseCache() { - return useCache; - } - - /** - * Gets a value indicating whether to wait for the model if it is not ready. - * @return A value indicating whether to wait for the model if it is not ready. - */ - public boolean isWaitForModel() { - return waitForModel; - } - } -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/ChatCompletionRequest.java.ignore b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/ChatCompletionRequest.java.ignore deleted file mode 100644 index 999728192..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/ChatCompletionRequest.java.ignore +++ /dev/null @@ -1,201 +0,0 @@ -package com.microsoft.semantickernel.aiservices.huggingface.models; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import javax.annotation.Nullable; - -// TODO Support TGI -public class ChatCompletionRequest { - - - /// - /// This is the default name when using TGI and will be ignored as the TGI will only target the current activated model. - /// - public static final String TextGenerationInferenceDefaultModel = "tgi"; - - - /// - /// Model name to use for generation. - /// - /// - /// When using TGI this parameter will be ignored. - /// - @Nullable - public final String model; - - /// - /// Indicates whether to get the response as stream or not. - /// - public final boolean stream; - - @Nullable - public final List messages; - - /// - /// Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each - /// output token returned in the content of message. - /// - @Nullable - public final Boolean logprobs; - - /// - /// An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, each with - /// an associated log probability. logprobs must be set to true if this parameter is used. - /// - @Nullable - public final Integer topLogProbs; - - /// - /// The maximum number of tokens that can be generated in the chat completion. - /// - @Nullable - public final Integer maxTokens; - - /// - /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, - /// increasing the model's likelihood to talk about new topics - /// - - @Nullable - public final Float presencePenalty; - /// - /// Up to 4 sequences where the API will stop generating further tokens. - /// - @Nullable - public final List stop; - - /// - /// The seed to use for generating a similar output. - /// - @Nullable - public final Long seed; - - /// - /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while - /// lower values like 0.2 will make it more focused and deterministic. - /// - /// We generally recommend altering this or `top_p` but not both. - /// - @Nullable - public final Float temperature; - - /// - /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the - /// tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. - /// - @Nullable - public final Float topP; - - public ChatCompletionRequest( - @JsonProperty("model") String model, - @JsonProperty("stream") boolean stream, - @JsonProperty("messages") List messages, - @JsonProperty("logprobs") Boolean logprobs, - - @Nullable - @JsonProperty("top_logprobs") Integer topLogProbs, - - @Nullable - @JsonProperty("max_tokens") Integer maxTokens, - - @Nullable - @JsonProperty("presence_penalty") Float presencePenalty, - @Nullable - @JsonProperty("stop") List stop, - - @Nullable - @JsonProperty("seed") Long seed, - @Nullable - @JsonProperty("temperature") Float temperature, - @Nullable - @JsonProperty("top_p") - Float topP - ) { - - this.model = model; - this.stream = stream; - this.messages = messages; - this.logprobs = logprobs; - this.topLogProbs = topLogProbs; - this.maxTokens = maxTokens; - this.presencePenalty = presencePenalty; - this.stop = stop; - this.seed = seed; - this.temperature = temperature; - this.topP = topP; - } - - public static class ChatMessageToolCall { - - @Nullable - private final String id; - - @Nullable - private final String type; - - private final ChatMessageFunction function; - - public ChatMessageToolCall( - @Nullable - @JsonProperty("id") String id, - @Nullable - @JsonProperty("type") String type, - @Nullable - @JsonProperty("function") ChatMessageFunction function - ) { - this.id = id; - this.type = type; - this.function = function; - } - } - - public static class ChatMessageFunction { - - @Nullable - public final String description; - @Nullable - public final String name; - @Nullable - public final String parameters; - - public ChatMessageFunction( - @JsonProperty("description") String description, - @JsonProperty("name") String name, - @JsonProperty("parameters") String parameters - ) { - this.description = description; - this.name = name; - this.parameters = parameters; - } - } - - public static class ChatMessage { - - @Nullable - public final String role; - @Nullable - public final String content; - @Nullable - public final String name; - @Nullable - public final List toolCalls; - - - public ChatMessage( - @Nullable - @JsonProperty("role") String role, - @Nullable - @JsonProperty("content") String content, - @Nullable - @JsonProperty("name") String name, - @Nullable - @JsonProperty("tool_calls") List toolCalls - ) { - this.role = role; - this.content = content; - this.name = name; - this.toolCalls = toolCalls; - } - - } -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceChatCompletionService.java.ignore b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceChatCompletionService.java.ignore deleted file mode 100644 index f6f05a9e0..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceChatCompletionService.java.ignore +++ /dev/null @@ -1,181 +0,0 @@ -package com.microsoft.semantickernel.aiservices.huggingface.services; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.huggingface.HuggingFaceClient; -import com.microsoft.semantickernel.aiservices.huggingface.models.ChatCompletionRequest; -import com.microsoft.semantickernel.aiservices.huggingface.models.HuggingFaceXMLPromptParser; -import com.microsoft.semantickernel.aiservices.huggingface.models.HuggingFaceXMLPromptParser.HuggingFaceParsedPrompt; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -// TODO Support TGI -public class HuggingFaceChatCompletionService implements ChatCompletionService { - - private final String modelId; - private final String serviceId; - private final HuggingFaceClient client; - - public HuggingFaceChatCompletionService( - String modelId, - String serviceId, - HuggingFaceClient client) { - this.modelId = modelId; - this.serviceId = serviceId; - this.client = client; - } - - public Mono>> getChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable HuggingFacePromptExecutionSettings executionSettings) { - - String model = modelId; - if (executionSettings.getModelId() != null && !executionSettings.getModelId().isEmpty()) { - model = executionSettings.getModelId(); - } - - ChatCompletionRequest request = new ChatCompletionRequest( - model, - false, - chatHistory - .getMessages() - .stream() - .map( - message -> { - return new ChatCompletionRequest.ChatMessage( - message.getAuthorRole().name(), - message.getContent(), - null, - null - ); - } - ) - .collect(Collectors.toList()), - executionSettings.getLogprobs(), - executionSettings.getTopLogProbs(), - executionSettings.getMaxTokens(), - new Float(executionSettings.getPresencePenalty()), - executionSettings.getStopSequences(), - executionSettings.getSeed(), - new Float(executionSettings.getTemperature()), - new Float(executionSettings.getTopP()) - ); - - return client - .getChatMessageContentsAsync(modelId, request) - .map(result -> { - return Collections.singletonList(new ChatMessageContent<>( - AuthorRole.SYSTEM, - result) - ); - }); - } - - @Override - public Mono>> getChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - - HuggingFacePromptExecutionSettings executionSettings; - if (invocationContext != null && invocationContext.getPromptExecutionSettings() != null) { - executionSettings = HuggingFacePromptExecutionSettings.fromExecutionSettings( - invocationContext.getPromptExecutionSettings()); - } else { - executionSettings = new HuggingFacePromptExecutionSettings( - PromptExecutionSettings.builder().build()); - } - - return getChatMessageContentsAsync(chatHistory, kernel, executionSettings); - - } - - @Override - public Mono>> getChatMessageContentsAsync( - String prompt, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - HuggingFaceParsedPrompt parsed = HuggingFaceXMLPromptParser.parse(prompt); - - ChatHistory history = new ChatHistory(); - parsed.getChatRequestMessages() - .forEach(message -> { - history.addMessage(AuthorRole.valueOf(message.role.toUpperCase(Locale.ROOT)), - message.content); - }); - - return getChatMessageContentsAsync(history, kernel, invocationContext); - - } - - @Nullable - @Override - public String getModelId() { - return modelId; - } - - @Nullable - @Override - public String getServiceId() { - return serviceId; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - @Nullable - private String modelId; - @Nullable - private HuggingFaceClient client; - @Nullable - private String serviceId; - - /** - * Sets the model ID for the service - * - * @param modelId The model ID - * @return The builder - */ - public Builder withModelId(String modelId) { - this.modelId = modelId; - return this; - } - - /** - * Sets the service ID for the service - * - * @param serviceId The service ID - * @return The builder - */ - public Builder withServiceId(String serviceId) { - this.serviceId = serviceId; - return this; - } - - public Builder withHuggingFaceClient(HuggingFaceClient client) { - this.client = client; - return this; - } - - public ChatCompletionService build() { - return new HuggingFaceChatCompletionService( - this.modelId, - this.serviceId, - this.client); - } - } - -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceXMLPromptParser.java.ignore b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceXMLPromptParser.java.ignore deleted file mode 100644 index 6e6474852..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/models/chat/HuggingFaceXMLPromptParser.java.ignore +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface.models; - -import com.azure.core.util.BinaryData; -import com.microsoft.semantickernel.aiservices.huggingface.models.ChatCompletionRequest.ChatMessage; -import com.microsoft.semantickernel.aiservices.huggingface.models.ChatCompletionRequest.ChatMessageFunction; -import com.microsoft.semantickernel.aiservices.huggingface.models.ChatCompletionRequest.ChatMessageToolCall; -import com.microsoft.semantickernel.services.chatcompletion.ChatPromptParseVisitor; -import com.microsoft.semantickernel.services.chatcompletion.ChatXMLPromptParser; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -// TODO Support TGI -public class HuggingFaceXMLPromptParser { - - private static final Logger LOGGER = LoggerFactory.getLogger(HuggingFaceXMLPromptParser.class); - - public static class HuggingFaceParsedPrompt { - - private final List chatRequestMessages; - private final List functions; - - protected HuggingFaceParsedPrompt( - List parsedMessages, - @Nullable List parsedFunctions - ) { - this.chatRequestMessages = parsedMessages; - if (parsedFunctions == null) { - parsedFunctions = new ArrayList<>(); - } - this.functions = parsedFunctions; - } - - public List getChatRequestMessages() { - return chatRequestMessages; - } - - public List getFunctions() { - return functions; - } - } - - private static class HuggingFaceChatPromptParseVisitor implements - ChatPromptParseVisitor { - - private HuggingFaceParsedPrompt parsedRaw; - private final List functionDefinitions = new ArrayList<>(); - private final List messages = new ArrayList<>(); - - @Override - public ChatPromptParseVisitor addMessage( - String role, - String content) { - messages.add(new ChatMessage( - role, - content, - null, - null)); - return this; - } - - @Override - public ChatPromptParseVisitor addFunction( - String name, - @Nullable - String description, - @Nullable - BinaryData parameters) { - - String paramString = null; - if (parameters != null) { - paramString = parameters.toString(); - } - - ChatMessageToolCall function = new ChatMessageToolCall( - name, - null, - new ChatMessageFunction( - description, - name, - paramString - ) - ); - - functionDefinitions.add(function); - - return this; - } - - @Override - public boolean areMessagesEmpty() { - return messages.isEmpty(); - } - - @Override - public ChatPromptParseVisitor fromRawPrompt( - String rawPrompt) { - - ChatMessage message = new ChatMessage( - "user", - rawPrompt, - null, - null - ); - - this.parsedRaw = new HuggingFaceParsedPrompt(Collections.singletonList(message), - null); - - return this; - } - - @Override - public HuggingFaceParsedPrompt get() { - if (parsedRaw != null) { - return parsedRaw; - } - - return new HuggingFaceParsedPrompt(messages, functionDefinitions); - } - - @Override - public ChatPromptParseVisitor reset() { - return new HuggingFaceChatPromptParseVisitor(); - } - } - - public static HuggingFaceParsedPrompt parse(String rawPrompt) { - ChatPromptParseVisitor visitor = ChatXMLPromptParser.parse( - rawPrompt, - new HuggingFaceChatPromptParseVisitor()); - - return visitor.get(); - } -} \ No newline at end of file diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java deleted file mode 100644 index adcabe7c4..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface.services; - -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.responseformat.ResponseFormat; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * Represents the settings for executing a prompt with the Hugging Face API. - */ -public class HuggingFacePromptExecutionSettings extends PromptExecutionSettings { - - @Nullable - private final Integer topK; - @Nullable - private final Double repetitionPenalty; - @Nullable - private final Double maxTime; - @Nullable - private final Boolean details; - @Nullable - private final Boolean logProbs; - @Nullable - private final Integer topLogProbs; - @Nullable - private final Long seed; - - /** - * Create a new instance of HuggingFacePromptExecutionSettings. - * - * @param copy The PromptExecutionSettings to copy. - */ - public HuggingFacePromptExecutionSettings(PromptExecutionSettings copy) { - super( - copy.getServiceId(), - copy.getModelId(), - copy.getTemperature(), - copy.getTopP(), - copy.getPresencePenalty(), - copy.getFrequencyPenalty(), - copy.getMaxTokens(), - copy.getResultsPerPrompt(), - copy.getBestOf(), - copy.getUser(), - copy.getStopSequences(), - copy.getTokenSelectionBiases(), - copy.getResponseFormat() == null ? null : copy.getResponseFormat()); - this.topK = null; - this.repetitionPenalty = null; - this.maxTime = null; - this.details = null; - this.logProbs = null; - this.topLogProbs = null; - this.seed = null; - } - - /** - * Create a new instance of PromptExecutionSettings. - * - * @param serviceId The id of the AI service to use for prompt execution. - * @param modelId The id of the model to use for prompt execution. - * @param temperature The temperature setting for prompt execution. - * @param topP The topP setting for prompt execution. - * @param presencePenalty The presence penalty setting for prompt execution. - * @param frequencyPenalty The frequency penalty setting for prompt execution. - * @param maxTokens The maximum number of tokens to generate in the output. - * @param resultsPerPrompt The number of results to generate for each prompt. - * @param bestOf The best of setting for prompt execution. - * @param user The user to associate with the prompt execution. - * @param stopSequences The stop sequences to use for prompt execution. - * @param tokenSelectionBiases The token selection biases to use for prompt execution. - * @param responseFormat The response format to use for prompt execution - * @param topK The topK setting for prompt execution. - * @param repetitionPenalty The repetition penalty setting for prompt execution. - * @param maxTime The max time setting for prompt execution. - * @param details The details setting for prompt execution. - * @param logProbs The logprobs setting for prompt execution. - * @param topLogProbs The top log probs setting for prompt execution. - * @param seed The seed setting for prompt execution - */ - public HuggingFacePromptExecutionSettings( - String serviceId, - String modelId, - Double temperature, - Double topP, - Double presencePenalty, - Double frequencyPenalty, - Integer maxTokens, - Integer resultsPerPrompt, - Integer bestOf, - String user, - @Nullable List stopSequences, - @Nullable Map tokenSelectionBiases, - @Nullable ResponseFormat responseFormat, - @Nullable Integer topK, - @Nullable Double repetitionPenalty, - @Nullable Double maxTime, - @Nullable Boolean details, - @Nullable Boolean logProbs, - @Nullable Integer topLogProbs, - @Nullable Long seed) { - super( - serviceId, modelId, temperature, topP, presencePenalty, frequencyPenalty, maxTokens, - resultsPerPrompt, bestOf, user, stopSequences, tokenSelectionBiases, responseFormat); - - this.topK = topK; - this.repetitionPenalty = repetitionPenalty; - this.maxTime = maxTime; - this.details = details; - this.logProbs = logProbs; - this.topLogProbs = topLogProbs; - this.seed = seed; - } - - /** - * Create a new instance of PromptExecutionSettings from a PromptExecutionSettings. - * This method handles the whether the PromptExecutionSettings is already a - * HuggingFacePromptExecutionSettings or a new instance needs to be created - * from the provided PromptExecutionSettings. - * @param promptExecutionSettings The PromptExecutionSettings to copy. - * @return The PromptExecutionSettings mapped to a HuggingFacePromptExecutionSettings. - */ - public static HuggingFacePromptExecutionSettings fromExecutionSettings( - PromptExecutionSettings promptExecutionSettings) { - if (promptExecutionSettings instanceof HuggingFacePromptExecutionSettings) { - return (HuggingFacePromptExecutionSettings) promptExecutionSettings; - } - - return new HuggingFacePromptExecutionSettings( - promptExecutionSettings.getServiceId(), - promptExecutionSettings.getModelId(), - promptExecutionSettings.getTemperature(), - promptExecutionSettings.getTopP(), - promptExecutionSettings.getPresencePenalty(), - promptExecutionSettings.getFrequencyPenalty(), - promptExecutionSettings.getMaxTokens(), - promptExecutionSettings.getResultsPerPrompt(), - promptExecutionSettings.getBestOf(), - promptExecutionSettings.getUser(), - promptExecutionSettings.getStopSequences(), - promptExecutionSettings.getTokenSelectionBiases(), - promptExecutionSettings.getResponseFormat() != null - ? promptExecutionSettings.getResponseFormat() - : null, - null, - null, - null, - null, - null, - null, - null); - } - - /** - * Gets the topK setting for prompt execution. - * @return The topK setting for prompt execution - */ - @Nullable - public Integer getTopK() { - return topK; - } - - /** - * Gets the repetition penalty setting for prompt execution. - * @return The repetition penalty setting for prompt execution - */ - @Nullable - public Double getRepetitionPenalty() { - return repetitionPenalty; - } - - /** - * Gets the max time setting for prompt execution. - * @return The max time setting for prompt execution - */ - @Nullable - public Double getMaxTime() { - return maxTime; - } - - /** - * Gets the details setting for prompt execution. - * @return The details setting for prompt execution - */ - @Nullable - public Boolean getDetails() { - return details; - } - - /** - * Gets the logprobs setting for prompt execution. - * @return The logprobs setting for prompt execution - */ - @Nullable - public Boolean getLogprobs() { - return logProbs; - } - - /** - * Gets the top log probs setting for prompt execution. - * @return The top log probs setting for prompt execution - */ - @Nullable - public Integer getTopLogProbs() { - return topLogProbs; - } - - /** - * Gets the seed setting for prompt execution. - * @return The seed setting for prompt execution - */ - @Nullable - public Long getSeed() { - return seed; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || !(o instanceof HuggingFacePromptExecutionSettings)) { - return false; - } - if (!super.equals(o)) { - return false; - } - HuggingFacePromptExecutionSettings that = (HuggingFacePromptExecutionSettings) o; - return Objects.equals(topK, that.topK) && - Objects.equals(repetitionPenalty, that.repetitionPenalty) && - Objects.equals(maxTime, that.maxTime) && - Objects.equals(details, that.details) && - Objects.equals(logProbs, that.logProbs) && - Objects.equals(topLogProbs, that.topLogProbs) && - Objects.equals(seed, that.seed); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), topK, repetitionPenalty, maxTime, details, logProbs, - topLogProbs, seed); - } -} diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFaceTextGenerationService.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFaceTextGenerationService.java deleted file mode 100644 index a08b42326..000000000 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFaceTextGenerationService.java +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.huggingface.services; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.huggingface.HuggingFaceClient; -import com.microsoft.semantickernel.aiservices.huggingface.models.TextGenerationRequest; -import com.microsoft.semantickernel.aiservices.huggingface.models.TextGenerationRequest.HuggingFaceTextOptions; -import com.microsoft.semantickernel.aiservices.huggingface.models.TextGenerationRequest.HuggingFaceTextParameters; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.textcompletion.TextContent; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * A service that generates text using the Hugging Face API. - */ -public class HuggingFaceTextGenerationService implements TextGenerationService { - - private final String modelId; - private final String serviceId; - private final HuggingFaceClient client; - - /** - * Create a new instance of HuggingFaceTextGenerationService. - * @param modelId The model ID. - * @param serviceId The service ID. - * @param client The Hugging Face client. - */ - public HuggingFaceTextGenerationService( - String modelId, - String serviceId, - HuggingFaceClient client) { - this.modelId = modelId; - this.serviceId = serviceId; - this.client = client; - } - - /** - * Get the response to a prompt. - * @param prompt The prompt. - * @param huggingFacePromptExecutionSettings The settings for executing the prompt. - * @param kernel The semantic kernel. - * @return The response to the prompt. - */ - public Mono> getTextContentsAsync( - String prompt, - @Nullable HuggingFacePromptExecutionSettings huggingFacePromptExecutionSettings, - @Nullable Kernel kernel) { - - HuggingFaceTextParameters textParameters = getHuggingFaceTextParameters( - huggingFacePromptExecutionSettings); - - TextGenerationRequest textGenerationRequest = new TextGenerationRequest( - prompt, - false, - textParameters, - new HuggingFaceTextOptions()); - - return client - .getTextContentsAsync(modelId, textGenerationRequest) - .map(result -> result - .stream() - .map(item -> new TextContent( - item.getGeneratedText() != null ? item.getGeneratedText() : "", - modelId, - FunctionResultMetadata.build(UUID.randomUUID().toString()))) - .collect(Collectors.toList())); - } - - @Override - public Mono> getTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel) { - - HuggingFacePromptExecutionSettings huggingFacePromptExecutionSettings = null; - - if (executionSettings != null) { - huggingFacePromptExecutionSettings = HuggingFacePromptExecutionSettings - .fromExecutionSettings( - executionSettings); - } - - return getTextContentsAsync( - prompt, - huggingFacePromptExecutionSettings, - kernel); - - } - - @Override - public Flux getStreamingTextContentsAsync(String prompt, - @Nullable PromptExecutionSettings executionSettings, @Nullable Kernel kernel) { - throw new SKException("Streaming text content is not supported"); - } - - private static @Nullable HuggingFaceTextParameters getHuggingFaceTextParameters( - @Nullable HuggingFacePromptExecutionSettings executionSettings) { - HuggingFaceTextParameters textParameters = null; - if (executionSettings != null) { - textParameters = new HuggingFaceTextParameters( - executionSettings.getTopK(), - executionSettings.getTopP(), - executionSettings.getTemperature(), - executionSettings.getRepetitionPenalty(), - executionSettings.getMaxTokens(), - executionSettings.getMaxTime(), - true, - executionSettings.getResultsPerPrompt(), - null, - executionSettings.getDetails()); - } - return textParameters; - } - - @Nullable - @Override - public String getModelId() { - return modelId; - } - - @Nullable - @Override - public String getServiceId() { - return serviceId; - } - - /** - * Create a new builder for HuggingFaceTextGenerationService. - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for HuggingFaceTextGenerationService. - */ - public static class Builder { - - @Nullable - protected String modelId; - @Nullable - protected HuggingFaceClient client; - @Nullable - protected String serviceId; - - /** - * Sets the model ID for the service - * - * @param modelId The model ID - * @return The builder - */ - public Builder withModelId(String modelId) { - this.modelId = modelId; - return this; - } - - /** - * Sets the service ID for the service - * - * @param serviceId The service ID - * @return The builder - */ - public Builder withServiceId(String serviceId) { - this.serviceId = serviceId; - return this; - } - - /** - * Sets the HuggingFaceClient for the service - * @param client The HuggingFaceClient - * @return The builder - */ - public Builder withHuggingFaceClient(HuggingFaceClient client) { - this.client = client; - return this; - } - - /** - * Builds the HuggingFaceTextGenerationService - * @return The HuggingFaceTextGenerationService - */ - public HuggingFaceTextGenerationService build() { - - if (this.modelId == null) { - throw new SKException( - "Model ID is required to build HuggingFaceTextGenerationService"); - } - - if (this.serviceId == null) { - throw new SKException( - "Service ID is required to build HuggingFaceTextGenerationService"); - } - - if (this.client == null) { - throw new SKException( - "HuggingFaceClient is required to build HuggingFaceTextGenerationService"); - } - - return new HuggingFaceTextGenerationService( - this.modelId, - this.serviceId, - this.client); - } - } -} diff --git a/aiservices/openai/pom.xml b/aiservices/openai/pom.xml deleted file mode 100644 index 992629a43..000000000 --- a/aiservices/openai/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - 4.0.0 - - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-aiservices-openai - Semantic Kernel OpenAI Services - OpenAI services for Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-data - provided - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - provided - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - provided - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - - - - com.azure - azure-ai-openai - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - - - javax.xml.stream - stax-api - provided - - - io.opentelemetry - opentelemetry-sdk - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.mockito - mockito-core - test - - - - com.github.victools - jsonschema-generator - true - - - com.github.victools - jsonschema-module-jackson - true - - - - - - - src/main/resources - true - - - - - diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/OpenAiService.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/OpenAiService.java deleted file mode 100644 index 0edee4767..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/OpenAiService.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai; - -import com.microsoft.semantickernel.services.AIService; -import javax.annotation.Nullable; - -/** - * Provides OpenAI service. - * @param the client type - */ -public abstract class OpenAiService implements AIService { - - private final Client client; - @Nullable - private final String serviceId; - private final String modelId; - private final String deploymentName; - - protected OpenAiService( - Client client, - @Nullable String serviceId, - String modelId, - String deploymentName) { - this.client = client; - this.serviceId = serviceId; - this.modelId = modelId; - this.deploymentName = deploymentName; - } - - @Nullable - @Override - public String getModelId() { - return modelId; - } - - @Override - @Nullable - public String getServiceId() { - return serviceId; - } - - /** - * Gets the client. - * @return the client - */ - protected Client getClient() { - return client; - } - - /** - * Gets the deployment name. - * @return the deployment name - */ - public String getDeploymentName() { - return deploymentName; - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiAudioToTextService.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiAudioToTextService.java deleted file mode 100644 index 7a126f6d8..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiAudioToTextService.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.audio; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.AudioTranscription; -import com.azure.ai.openai.models.AudioTranscriptionFormat; -import com.azure.ai.openai.models.AudioTranscriptionOptions; -import com.microsoft.semantickernel.aiservices.openai.OpenAiService; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.services.audio.AudioContent; -import com.microsoft.semantickernel.services.audio.AudioToTextExecutionSettings; -import com.microsoft.semantickernel.services.audio.AudioToTextService; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -/** - * Provides OpenAi implementation of audio to text service. - */ -public class OpenAiAudioToTextService extends OpenAiService - implements AudioToTextService { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAiAudioToTextService.class); - - /** - * Creates an instance of OpenAi audio to text service. - * - * @param client OpenAI client. - * @param modelId The model ID. - * @param deploymentName The deployment name. - */ - public OpenAiAudioToTextService( - OpenAIAsyncClient client, - String modelId, - String deploymentName) { - super(client, null, modelId, deploymentName); - } - - @Override - public Mono getTextContentsAsync( - AudioContent content, - @Nullable AudioToTextExecutionSettings executionSettings) { - - AudioTranscriptionOptions options = convertOptions(content, executionSettings); - - // TODO: Should use getAudioTranscriptionTextWithResponse, and OpenAIRequestSettings.getRequestOptions() - // however currently this breaks the request - return getClient() - .getAudioTranscription( - getDeploymentName(), - options.getFilename(), - options) - .map(AudioTranscription::getText); - } - - private AudioTranscriptionOptions convertOptions( - AudioContent content, - @Nullable AudioToTextExecutionSettings executionSettings) { - AudioTranscriptionOptions options = new AudioTranscriptionOptions(content.getData()); - - options.setModel(getModelId()); - if (executionSettings == null) { - return options; - } - - if (executionSettings.getResponseFormat() != null) { - options.setResponseFormat( - AudioTranscriptionFormat.fromString(executionSettings.getResponseFormat())); - } - - if (executionSettings.getFilename() != null) { - options.setFilename(executionSettings.getFilename()); - } - - if (executionSettings.getLanguage() != null) { - options.setLanguage(executionSettings.getLanguage()); - } - - if (executionSettings.getPrompt() != null) { - options.setPrompt(executionSettings.getPrompt()); - } - - if (executionSettings.getTemperature() != null) { - options.setTemperature(executionSettings.getTemperature()); - } - return options; - } - - /** - * Builder for OpenAiAudioToTextService. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Represents a builder for OpenAiAudioToTextService. - */ - public static class Builder extends AudioToTextService.Builder { - - /** - * builds the OpenAiAudioToTextService. - */ - @Override - public AudioToTextService build() { - if (client == null) { - throw new SKException("OpenAI client is required"); - } - - if (modelId == null) { - throw new SKException("Model id is required"); - } - - if (deploymentName == null) { - LOGGER.debug("Deployment name is not provided, using model id as deployment name"); - deploymentName = modelId; - } - - return new OpenAiAudioToTextService(client, modelId, deploymentName); - } - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiTextToAudioService.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiTextToAudioService.java deleted file mode 100644 index dc748af7d..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/audio/OpenAiTextToAudioService.java +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.audio; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.SpeechGenerationOptions; -import com.azure.ai.openai.models.SpeechGenerationResponseFormat; -import com.azure.ai.openai.models.SpeechVoice; -import com.microsoft.semantickernel.aiservices.openai.OpenAiService; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.services.audio.AudioContent; -import com.microsoft.semantickernel.services.audio.TextToAudioExecutionSettings; -import com.microsoft.semantickernel.services.audio.TextToAudioService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -/** - * Provides OpenAi implementation of text to audio service. - */ -public class OpenAiTextToAudioService extends OpenAiService - implements TextToAudioService { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAiTextToAudioService.class); - - /** - * Creates an instance of OpenAi text to audio service. - * - * @param client OpenAI client. - * @param modelId The model ID. - * @param deploymentName The deployment name. - */ - public OpenAiTextToAudioService( - OpenAIAsyncClient client, - String modelId, - String deploymentName) { - super(client, null, modelId, deploymentName); - } - - @Override - public Mono getAudioContentAsync( - String text, - TextToAudioExecutionSettings executionSettings) { - - SpeechGenerationOptions options = convertOptions(text, executionSettings); - - return getClient().generateSpeechFromText(getDeploymentName(), options) - .map(response -> new AudioContent(response.toBytes(), getModelId())); - } - - private SpeechGenerationOptions convertOptions( - String text, - TextToAudioExecutionSettings executionSettings) { - SpeechGenerationOptions options = new SpeechGenerationOptions( - text, - SpeechVoice.fromString(executionSettings.getVoice())); - - options.setModel(getModelId()); - - if (executionSettings.getResponseFormat() != null) { - options.setResponseFormat( - SpeechGenerationResponseFormat.fromString(executionSettings.getResponseFormat())); - } - - if (executionSettings.getSpeed() != null) { - options.setSpeed(executionSettings.getSpeed()); - } - - return options; - } - - /** - * Creates a new builder. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Represents a builder for OpenAi text to audio service. - */ - public static class Builder extends TextToAudioService.Builder { - - /** - * Builds the OpenAi text to audio service. - * - * @return The OpenAi text to audio service. - */ - @Override - public TextToAudioService build() { - if (client == null) { - throw new SKException("OpenAI client is required"); - } - - if (modelId == null) { - throw new SKException("Model id is required"); - } - - if (deploymentName == null) { - LOGGER.debug("Deployment name is not provided, using model id as deployment name"); - deploymentName = modelId; - } - - return new OpenAiTextToAudioService(client, modelId, deploymentName); - } - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/BinaryDataUtils.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/BinaryDataUtils.java deleted file mode 100644 index 9a3189a7e..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/BinaryDataUtils.java +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.core.util.BinaryData; -import javax.annotation.Nullable; - -public class BinaryDataUtils { - - @Nullable - public static String toString(@Nullable BinaryData b) { - if (b == null) { - return null; - } - return b.toString(); - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java deleted file mode 100644 index 8256bb002..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java +++ /dev/null @@ -1,1334 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.ChatChoice; -import com.azure.ai.openai.models.ChatCompletions; -import com.azure.ai.openai.models.ChatCompletionsFunctionToolCall; -import com.azure.ai.openai.models.ChatCompletionsFunctionToolDefinition; -import com.azure.ai.openai.models.ChatCompletionsFunctionToolDefinitionFunction; -import com.azure.ai.openai.models.ChatCompletionsJsonResponseFormat; -import com.azure.ai.openai.models.ChatCompletionsNamedToolSelection; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.ChatCompletionsTextResponseFormat; -import com.azure.ai.openai.models.ChatCompletionsToolCall; -import com.azure.ai.openai.models.ChatCompletionsToolDefinition; -import com.azure.ai.openai.models.ChatCompletionsToolSelection; -import com.azure.ai.openai.models.ChatCompletionsToolSelectionPreset; -import com.azure.ai.openai.models.ChatMessageImageContentItem; -import com.azure.ai.openai.models.ChatMessageImageDetailLevel; -import com.azure.ai.openai.models.ChatMessageImageUrl; -import com.azure.ai.openai.models.ChatRequestAssistantMessage; -import com.azure.ai.openai.models.ChatRequestFunctionMessage; -import com.azure.ai.openai.models.ChatRequestMessage; -import com.azure.ai.openai.models.ChatRequestSystemMessage; -import com.azure.ai.openai.models.ChatRequestToolMessage; -import com.azure.ai.openai.models.ChatRequestUserMessage; -import com.azure.ai.openai.models.ChatResponseMessage; -import com.azure.ai.openai.models.CompletionsUsage; -import com.azure.ai.openai.models.FunctionCall; -import com.azure.ai.openai.models.FunctionDefinition; -import com.azure.json.JsonOptions; -import com.azure.json.implementation.DefaultJsonReader; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ContainerNode; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.OpenAiService; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat.ChatCompletionsJsonSchemaResponseFormat; -import com.microsoft.semantickernel.aiservices.openai.implementation.OpenAIRequestSettings; -import com.microsoft.semantickernel.contents.FunctionCallContent; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes; -import com.microsoft.semantickernel.exceptions.SKCheckedException; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.functionchoice.AutoFunctionChoiceBehavior; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior; -import com.microsoft.semantickernel.functionchoice.NoneFunctionChoiceBehavior; -import com.microsoft.semantickernel.functionchoice.RequiredFunctionChoiceBehavior; -import com.microsoft.semantickernel.hooks.KernelHookEvent; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.hooks.PostChatCompletionEvent; -import com.microsoft.semantickernel.hooks.PreChatCompletionEvent; -import com.microsoft.semantickernel.hooks.PreToolCallEvent; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.implementation.telemetry.ChatCompletionSpan; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.orchestration.responseformat.JsonResponseSchema; -import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import com.microsoft.semantickernel.services.chatcompletion.StreamingChatContent; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageContentType; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent; -import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.CheckReturnValue; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * OpenAI chat completion service. - */ -public class OpenAIChatCompletion extends OpenAiService - implements ChatCompletionService { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAIChatCompletion.class); - - protected OpenAIChatCompletion( - OpenAIAsyncClient client, - String deploymentName, - String modelId, - @Nullable String serviceId) { - super(client, serviceId, modelId, deploymentName); - } - - /** - * Create a new instance of {@link OpenAIChatCompletion.Builder}. - * - * @return a new instance of {@link OpenAIChatCompletion.Builder} - */ - public static OpenAIChatCompletion.Builder builder() { - return new OpenAIChatCompletion.Builder(); - } - - @Override - public Mono>> getChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - - List chatRequestMessages = getChatRequestMessages(chatHistory); - - ChatMessages messages = new ChatMessages(chatRequestMessages); - - return internalChatMessageContentsAsync( - messages, - kernel, - invocationContext) - .flatMap(history -> { - try { - ChatHistory chatHistoryResult; - - if (invocationContext != null - && invocationContext.returnMode() == InvocationReturnMode.FULL_HISTORY) { - chatHistoryResult = new ChatHistory(chatHistory.getMessages()); - } else { - chatHistoryResult = new ChatHistory(); - } - - chatHistoryResult.addAll( - new ChatHistory(toOpenAIChatMessageContent(history.newMessages))); - chatHistoryResult.addAll(new ChatHistory(history.newChatMessageContent)); - - if (invocationContext != null - && invocationContext - .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { - chatHistoryResult = new ChatHistory( - Collections.singletonList( - CollectionUtil.getLastOrNull(chatHistoryResult.getMessages()))); - } - - return Mono.just(chatHistoryResult.getMessages()); - } catch (Exception e) { - return Mono.error(e); - } - }); - } - - @Override - public Mono>> getChatMessageContentsAsync( - String prompt, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - ParsedPrompt parsedPrompt = OpenAiXMLPromptParser.parse(prompt); - - ChatMessages messages = new ChatMessages(parsedPrompt.getChatRequestMessages()); - - return internalChatMessageContentsAsync( - messages, - kernel, - invocationContext) - .flatMap(m -> { - try { - ChatHistory result = new ChatHistory(toOpenAIChatMessageContent(m.allMessages)); - - result.addAll(new ChatHistory(m.newChatMessageContent)); - - if (invocationContext != null - && invocationContext - .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { - result = new ChatHistory( - Collections.singletonList( - CollectionUtil.getLastOrNull(result.getMessages()))); - } - - return Mono.just(result.getMessages()); - } catch (SKCheckedException e) { - return Mono.error(e); - } - }); - } - - @Override - public Flux> getStreamingChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - if (invocationContext != null && - invocationContext.getToolCallBehavior() != null && - invocationContext.getToolCallBehavior().isAutoInvokeAllowed()) { - throw new SKException( - "ToolCallBehavior auto-invoke is not supported for streaming chat message contents"); - } - - if (invocationContext != null && - invocationContext.getFunctionChoiceBehavior() != null && - invocationContext.getFunctionChoiceBehavior() instanceof AutoFunctionChoiceBehavior && - ((AutoFunctionChoiceBehavior) invocationContext.getFunctionChoiceBehavior()) - .isAutoInvoke()) { - throw new SKException( - "FunctionChoiceBehavior auto-invoke is not supported for streaming chat message contents"); - } - - if (invocationContext != null - && invocationContext.returnMode() != InvocationReturnMode.NEW_MESSAGES_ONLY) { - throw new SKException( - "Streaming chat message contents only supports NEW_MESSAGES_ONLY return mode"); - } - - List chatRequestMessages = getChatRequestMessages(chatHistory); - - ChatMessages messages = new ChatMessages(chatRequestMessages); - - List functions = new ArrayList<>(); - if (kernel != null) { - kernel.getPlugins() - .forEach(plugin -> plugin.getFunctions().forEach((name, function) -> functions - .add(OpenAIFunction.build(function.getMetadata(), plugin.getName())))); - } - - OpenAIToolCallConfig toolCallConfig = getToolCallConfig( - invocationContext, - functions, - messages.allMessages, - 0); - - ChatCompletionsOptions options = executeHook( - invocationContext, - kernel, - new PreChatCompletionEvent( - getCompletionsOptions( - this, - messages.allMessages, - invocationContext, - toolCallConfig))) - .getOptions(); - - return getClient() - .getChatCompletionsStreamWithResponse( - getDeploymentName(), - options, - OpenAIRequestSettings.getRequestOptions()) - .flatMap(completionsResult -> { - if (completionsResult.getStatusCode() >= 400) { - //SemanticKernelTelemetry.endSpanWithError(span); - return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR, - "Request failed: " + completionsResult.getStatusCode())); - } - //SemanticKernelTelemetry.endSpanWithUsage(span, completionsResult.getValue().getUsage()); - - return Mono.just(completionsResult.getValue()); - }) - .flatMap(completions -> { - return Flux.fromIterable(completions.getChoices()) - .map(message -> { - AuthorRole role = message.getDelta().getRole() == null - ? AuthorRole.ASSISTANT - : AuthorRole.valueOf(message.getDelta().getRole().toString() - .toUpperCase(Locale.ROOT)); - - return new OpenAIStreamingChatMessageContent<>( - completions.getId(), - role, - message.getDelta().getContent(), - getModelId(), - null, - null, - null, - Arrays.asList()); - }); - }); - } - - @Override - public Flux> getStreamingChatMessageContentsAsync( - String prompt, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - return getStreamingChatMessageContentsAsync( - new ChatHistory().addUserMessage(prompt), - kernel, - invocationContext); - } - - // Holds messages temporarily as we build up our result - private static class ChatMessages { - - private final List newMessages; - private final List allMessages; - private final List> newChatMessageContent; - - public ChatMessages(List allMessages) { - this.allMessages = Collections.unmodifiableList(allMessages); - this.newMessages = Collections.unmodifiableList(new ArrayList<>()); - this.newChatMessageContent = Collections.unmodifiableList(new ArrayList<>()); - } - - private ChatMessages( - List allMessages, - List newMessages, - List> newChatMessageContent) { - this.allMessages = Collections.unmodifiableList(allMessages); - this.newMessages = Collections.unmodifiableList(newMessages); - this.newChatMessageContent = Collections.unmodifiableList(newChatMessageContent); - } - - @CheckReturnValue - public ChatMessages addAll(List requestMessage) { - List tmpAllMessages = new ArrayList<>(allMessages); - List tmpNewMessages = new ArrayList<>(newMessages); - tmpAllMessages.addAll(requestMessage); - tmpNewMessages.addAll(requestMessage); - return new ChatMessages( - tmpAllMessages, - tmpNewMessages, - newChatMessageContent); - } - - @CheckReturnValue - public ChatMessages add(ChatRequestMessage requestMessage) { - return addAll(Arrays.asList(requestMessage)); - } - - @CheckReturnValue - public ChatMessages addChatMessage(List> chatMessageContent) { - ArrayList> tmpChatMessageContent = new ArrayList<>( - newChatMessageContent); - tmpChatMessageContent.addAll(chatMessageContent); - - return new ChatMessages( - allMessages, - newMessages, - tmpChatMessageContent); - } - - /** - * Checks that the two messages have a similar history - * - * @param messages The messages to merge in - * @return The merged chat messages - */ - boolean assertCommonHistory(List messages) { - int index = 0; - while (index < messages.size() && index < this.allMessages.size()) { - ChatRequestMessage a = messages.get(index); - ChatRequestMessage b = this.allMessages.get(index); - - boolean matches = false; - if (a instanceof ChatRequestAssistantMessage - && b instanceof ChatRequestAssistantMessage) { - matches = Objects.equals(((ChatRequestAssistantMessage) a).getContent(), - ((ChatRequestAssistantMessage) b).getContent()); - } else if (a instanceof ChatRequestSystemMessage - && b instanceof ChatRequestSystemMessage) { - matches = Objects.equals(((ChatRequestSystemMessage) a).getContent(), - ((ChatRequestSystemMessage) b).getContent()); - } else if (a instanceof ChatRequestUserMessage - && b instanceof ChatRequestUserMessage) { - matches = Objects.equals(((ChatRequestUserMessage) a).getContent(), - ((ChatRequestUserMessage) b).getContent()); - } else if (a instanceof ChatRequestFunctionMessage - && b instanceof ChatRequestFunctionMessage) { - matches = Objects.equals(((ChatRequestFunctionMessage) a).getContent(), - ((ChatRequestFunctionMessage) b).getContent()); - } else if (a instanceof ChatRequestToolMessage - && b instanceof ChatRequestToolMessage) { - matches = Objects.equals(((ChatRequestToolMessage) a).getContent(), - ((ChatRequestToolMessage) b).getContent()); - } - - if (!matches) { - LOGGER.warn("Messages do not match at index: " + index - + " you might be merging unrelated message histories"); - return false; - } - - index++; - } - - return true; - - } - } - - private Mono internalChatMessageContentsAsync( - ChatMessages messages, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext) { - - List functions = new ArrayList<>(); - if (kernel != null) { - kernel.getPlugins() - .forEach(plugin -> plugin.getFunctions().forEach((name, function) -> functions - .add(OpenAIFunction.build(function.getMetadata(), plugin.getName())))); - } - - return internalChatMessageContentsAsync( - messages, - kernel, - functions, - invocationContext, - 0); - } - - private Mono internalChatMessageContentsAsync( - ChatMessages messages, - @Nullable Kernel kernel, - List functions, - @Nullable InvocationContext invocationContext, - int requestIndex) { - - OpenAIToolCallConfig toolCallConfig = getToolCallConfig( - invocationContext, - functions, - messages.allMessages, - requestIndex); - - ChatCompletionsOptions options = executeHook( - invocationContext, - kernel, - new PreChatCompletionEvent( - getCompletionsOptions( - this, - messages.allMessages, - invocationContext, - toolCallConfig))) - .getOptions(); - - return Mono.deferContextual(contextView -> { - ChatCompletionSpan span = ChatCompletionSpan.startChatCompletionSpan( - SemanticKernelTelemetry.getTelemetry(invocationContext), - contextView, - getModelId(), - SemanticKernelTelemetry.OPEN_AI_PROVIDER, - options.getMaxTokens(), - options.getTemperature(), - options.getTopP()); - - return getClient() - .getChatCompletionsWithResponse(getDeploymentName(), options, - OpenAIRequestSettings.getRequestOptions()) - .contextWrite(span.getReactorContextModifier()) - .flatMap(completionsResult -> { - if (completionsResult.getStatusCode() >= 400) { - return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR, - "Request failed: " + completionsResult.getStatusCode())); - } - - return Mono.just(completionsResult.getValue()); - }) - .doOnError(span::endSpanWithError) - .doOnSuccess(span::endSpanWithUsage) - .doOnTerminate(span::close); - }) - .flatMap(completions -> { - List responseMessages = completions - .getChoices() - .stream() - .map(ChatChoice::getMessage) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - // execute post chat completion hook - executeHook(invocationContext, kernel, new PostChatCompletionEvent(completions)); - - // Just return the result: - // If auto-invoking is not enabled - // Or if we are auto-invoking, but we somehow end up with other than 1 choice even though only 1 was requested - if (toolCallConfig == null || !toolCallConfig.isAutoInvoke() - || responseMessages.size() != 1) { - List> chatMessageContents = getChatMessageContentsAsync( - completions); - return Mono.just(messages.addChatMessage(chatMessageContents)); - } - - // Or if there are no tool calls to be done - ChatResponseMessage response = responseMessages.get(0); - List toolCalls = response.getToolCalls(); - if (toolCalls == null || toolCalls.isEmpty()) { - List> chatMessageContents = getChatMessageContentsAsync( - completions); - return Mono.just(messages.addChatMessage(chatMessageContents)); - } - - ChatRequestAssistantMessage requestMessage = new ChatRequestAssistantMessage( - response.getContent()); - requestMessage.setToolCalls(toolCalls); - - // Add the original assistant message to the chat options; this is required for the service - // to understand the tool call responses - ChatMessages messagesWithToolCall = messages.add(requestMessage); - - return Flux - .fromIterable(toolCalls) - .reduce( - Mono.just(messagesWithToolCall), - (requestMessages, toolCall) -> { - if (toolCall instanceof ChatCompletionsFunctionToolCall) { - return performToolCall(kernel, invocationContext, requestMessages, - toolCall); - } - - return requestMessages; - }) - .flatMap(it -> it) - .flatMap(msgs -> { - return internalChatMessageContentsAsync(msgs, kernel, functions, - invocationContext, requestIndex + 1); - }) - .onErrorResume(e -> { - - LOGGER.warn("Tool invocation attempt failed: ", e); - - // If FunctionInvocationError occurred and there are still attempts left, retry, else exit - if (requestIndex < MAXIMUM_INFLIGHT_AUTO_INVOKES) { - ChatMessages currentMessages = messages; - if (e instanceof FunctionInvocationError) { - currentMessages.assertCommonHistory( - ((FunctionInvocationError) e).getMessages()); - - currentMessages = new ChatMessages( - ((FunctionInvocationError) e).getMessages()); - } - return internalChatMessageContentsAsync( - currentMessages, - kernel, - functions, - invocationContext, - requestIndex + 1); - } else { - return Mono.error(e); - } - }); - }); - } - - private Mono performToolCall( - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext, - Mono requestMessages, - ChatCompletionsToolCall toolCall) { - - return requestMessages - .flatMap(messages -> { - try { - // OpenAI only supports function tool call at the moment - ChatCompletionsFunctionToolCall functionToolCall = (ChatCompletionsFunctionToolCall) toolCall; - if (kernel == null) { - return Mono.error(new SKException( - "A tool call was requested, but no kernel was provided to the invocation, this is a unsupported configuration")); - } - - ContextVariableTypes contextVariableTypes = invocationContext == null - ? new ContextVariableTypes() - : invocationContext.getContextVariableTypes(); - - return invokeFunctionTool( - kernel, - invocationContext, - functionToolCall, - contextVariableTypes) - .map(functionResult -> { - // Add chat request tool message to the chat options - ChatRequestMessage requestToolMessage = new ChatRequestToolMessage( - functionResult.getResult(), - functionToolCall.getId()); - - return messages.add(requestToolMessage); - }) - .switchIfEmpty(Mono.fromSupplier( - () -> { - ChatRequestMessage requestToolMessage = new ChatRequestToolMessage( - "Completed successfully with no return value", - functionToolCall.getId()); - - return messages.add(requestToolMessage); - })) - .onErrorResume(e -> emitError(toolCall, messages, e)); - } catch (Exception e) { - return emitError(toolCall, messages, e); - } - }); - } - - private Mono emitError( - ChatCompletionsToolCall toolCall, - ChatMessages msgs, - Throwable e) { - msgs = msgs.add(new ChatRequestToolMessage( - "Call failed: " + e.getMessage(), - toolCall.getId())); - - return Mono.error(new FunctionInvocationError(e, msgs.allMessages)); - } - - /** - * Exception to be thrown when a function invocation fails. - */ - private static class FunctionInvocationError extends SKException { - - private final List messages; - - public FunctionInvocationError(Throwable e, List msgs) { - super(e.getMessage(), e); - this.messages = msgs; - } - - public List getMessages() { - return messages; - } - } - - @SuppressWarnings("StringSplitter") - private Mono> invokeFunctionTool( - Kernel kernel, - @Nullable InvocationContext invocationContext, - ChatCompletionsFunctionToolCall toolCall, - ContextVariableTypes contextVariableTypes) { - - try { - FunctionCallContent functionCallContent = extractFunctionCallContent(toolCall); - String pluginName = functionCallContent.getPluginName(); - if (pluginName == null || pluginName.isEmpty()) { - return Mono.error( - new SKException("Plugin name is required for function tool call")); - } - - KernelFunction function = kernel.getFunction( - pluginName, - functionCallContent.getFunctionName()); - - PreToolCallEvent hookResult = executeHook(invocationContext, kernel, - new PreToolCallEvent( - functionCallContent.getFunctionName(), - functionCallContent.getArguments(), - function, - contextVariableTypes)); - - function = hookResult.getFunction(); - KernelArguments arguments = hookResult.getArguments(); - - return function - .invokeAsync(kernel) - .withArguments(arguments) - .withTypes(invocationContext.getContextVariableTypes()) - .withTypes(contextVariableTypes) - .withResultType(contextVariableTypes.getVariableTypeForClass(String.class)); - } catch (JsonProcessingException e) { - return Mono.error(new SKException("Failed to parse tool arguments", e)); - } - } - - private static T executeHook( - @Nullable InvocationContext invocationContext, - @Nullable Kernel kernel, - T event) { - KernelHooks kernelHooks = null; - if (kernel == null) { - if (invocationContext != null) { - kernelHooks = invocationContext.getKernelHooks(); - } - } else { - kernelHooks = KernelHooks.merge( - kernel.getGlobalKernelHooks(), - invocationContext != null ? invocationContext.getKernelHooks() : null); - } - if (kernelHooks == null) { - return event; - } - return kernelHooks.executeHooks(event); - } - - @SuppressWarnings("StringSplitter") - private FunctionCallContent extractFunctionCallContent( - ChatCompletionsFunctionToolCall toolCall) - throws JsonProcessingException { - - // Split the full name of a function into plugin and function name - String name = toolCall.getFunction().getName(); - String[] parts = name.split(OpenAIFunction.getNameSeparator()); - String pluginName = parts.length > 1 ? parts[0] : ""; - String fnName = parts.length > 1 ? parts[1] : parts[0]; - - KernelArguments arguments = KernelArguments.builder().build(); - - ObjectMapper mapper = new ObjectMapper(); - JsonNode jsonToolCallArguments = mapper.readTree(toolCall.getFunction().getArguments()); - - jsonToolCallArguments.fields().forEachRemaining( - entry -> { - if (entry.getValue() instanceof ContainerNode) { - arguments.put(entry.getKey(), - ContextVariable.of(entry.getValue().toPrettyString())); - } else { - arguments.put(entry.getKey(), - ContextVariable.of(entry.getValue().asText())); - } - }); - - return new FunctionCallContent( - fnName, - pluginName, - toolCall.getId(), - arguments); - } - - private List> getChatMessageContentsAsync( - ChatCompletions completions) { - FunctionResultMetadata completionMetadata = FunctionResultMetadata.build( - completions.getId(), - completions.getUsage(), - completions.getCreatedAt()); - - List responseMessages = completions - .getChoices() - .stream() - .map(ChatChoice::getMessage) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - List> chatMessageContent = responseMessages - .stream() - .map(response -> { - try { - return new OpenAIChatMessageContent<>( - AuthorRole.ASSISTANT, - response.getContent(), - this.getModelId(), - null, - null, - completionMetadata, - formFunctionCallContents(response)); - } catch (SKCheckedException e) { - LOGGER.warn("Failed to form chat message content", e); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - return chatMessageContent; - } - - private List> toOpenAIChatMessageContent( - List requestMessages) throws SKCheckedException { - try { - return requestMessages - .stream() - .map(message -> { - if (message instanceof ChatRequestUserMessage) { - return new OpenAIChatMessageContent<>( - AuthorRole.USER, - BinaryDataUtils - .toString(((ChatRequestUserMessage) message).getContent()), - null, - null, - null, - null, - null); - } else if (message instanceof ChatRequestSystemMessage) { - return new OpenAIChatMessageContent<>( - AuthorRole.SYSTEM, - BinaryDataUtils - .toString(((ChatRequestSystemMessage) message).getContent()), - null, - null, - null, - null, - null); - } else if (message instanceof ChatRequestAssistantMessage) { - try { - List calls = getFunctionCallContents( - ((ChatRequestAssistantMessage) message).getToolCalls()); - return new OpenAIChatMessageContent<>( - AuthorRole.ASSISTANT, - BinaryDataUtils - .toString(((ChatRequestAssistantMessage) message).getContent()), - null, - null, - null, - null, - calls); - } catch (SKCheckedException e) { - throw SKException.build("Failed to form assistant message", e); - } - } else if (message instanceof ChatRequestToolMessage) { - return new OpenAIChatMessageContent<>( - AuthorRole.TOOL, - BinaryDataUtils - .toString(((ChatRequestToolMessage) message).getContent()), - null, - null, - null, - FunctionResultMetadata.build( - ((ChatRequestToolMessage) message).getToolCallId(), - null, - null), - null); - } - - throw new SKException( - "Unknown message type: " + message.getClass().getSimpleName()); - }) - .collect(Collectors.toList()); - } catch (SKException e) { - throw SKCheckedException.build("Failed to form OpenAI chat message content", e); - } - } - - @Nullable - private List getFunctionCallContents( - @Nullable List toolCalls) throws SKCheckedException { - if (toolCalls == null || toolCalls.isEmpty()) { - return null; - } - - try { - return toolCalls - .stream() - .map(call -> { - if (call instanceof ChatCompletionsFunctionToolCall) { - try { - return extractFunctionCallContent( - (ChatCompletionsFunctionToolCall) call); - } catch (JsonProcessingException e) { - throw SKException.build("Failed to parse tool arguments", e); - } - } else { - throw new SKException( - "Unknown tool call type: " + call.getClass().getSimpleName()); - } - }) - .collect(Collectors.toList()); - } catch (SKException e) { - throw SKCheckedException.build("Failed to form tool call", e); - } - } - - @Nullable - private List formFunctionCallContents( - ChatResponseMessage response) throws SKCheckedException { - if (response.getToolCalls() == null || response.getToolCalls().isEmpty()) { - return null; - } - try { - return response - .getToolCalls() - .stream() - .map(call -> { - if (call instanceof ChatCompletionsFunctionToolCall) { - try { - return extractFunctionCallContent( - (ChatCompletionsFunctionToolCall) call); - } catch (JsonProcessingException e) { - throw SKException.build("Failed to parse tool arguments", e); - } - } else { - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } catch (SKException e) { - throw SKCheckedException.build("Failed to form tool call", e); - } - } - - private static ChatCompletionsOptions getCompletionsOptions( - ChatCompletionService chatCompletionService, - List chatRequestMessages, - @Nullable InvocationContext invocationContext, - @Nullable OpenAIToolCallConfig toolCallConfig) { - - chatRequestMessages = chatRequestMessages - .stream() - .map(OpenAiXMLPromptParser::unescapeRequest) - .collect(Collectors.toList()); - - ChatCompletionsOptions options = new ChatCompletionsOptions(chatRequestMessages) - .setModel(chatCompletionService.getModelId()); - - if (toolCallConfig != null) { - options.setTools(toolCallConfig.getTools()); - options.setToolChoice(toolCallConfig.getToolChoice()); - - if (toolCallConfig.getOptions() != null) { - options.setParallelToolCalls(toolCallConfig.getOptions().isParallelCallsAllowed()); - } - } - - PromptExecutionSettings promptExecutionSettings = invocationContext != null - ? invocationContext.getPromptExecutionSettings() - : null; - - if (promptExecutionSettings == null) { - return options; - } - - if (promptExecutionSettings.getResultsPerPrompt() < 1 - || promptExecutionSettings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format("Results per prompt must be in range between 1 and %d, inclusive.", - MAX_RESULTS_PER_PROMPT)); - } - - Map logit = null; - if (promptExecutionSettings.getTokenSelectionBiases() != null) { - logit = promptExecutionSettings - .getTokenSelectionBiases() - .entrySet() - .stream() - .collect(Collectors.toMap( - entry -> entry.getKey().toString(), - Map.Entry::getValue)); - } - - options - .setTemperature(promptExecutionSettings.getTemperature()) - .setTopP(promptExecutionSettings.getTopP()) - .setPresencePenalty(promptExecutionSettings.getPresencePenalty()) - .setFrequencyPenalty(promptExecutionSettings.getFrequencyPenalty()) - .setPresencePenalty(promptExecutionSettings.getPresencePenalty()) - .setMaxTokens(promptExecutionSettings.getMaxTokens()) - .setN(promptExecutionSettings.getResultsPerPrompt()) - // Azure OpenAI WithData API does not allow to send empty array of stop sequences - // Gives back "Validation error at #/stop/str: Input should be a valid string\nValidation error at #/stop/list[str]: List should have at least 1 item after validation, not 0" - .setStop(promptExecutionSettings.getStopSequences() == null - || promptExecutionSettings.getStopSequences().isEmpty() ? null - : promptExecutionSettings.getStopSequences()) - .setUser(promptExecutionSettings.getUser()) - .setLogitBias(logit); - - if (promptExecutionSettings.getResponseFormat() != null) { - switch (promptExecutionSettings.getResponseFormat().getType()) { - case JSON_SCHEMA: - JsonResponseSchema schema = ((JsonSchemaResponseFormat) promptExecutionSettings - .getResponseFormat()) - .getJsonSchema(); - - options.setResponseFormat(new ChatCompletionsJsonSchemaResponseFormat(schema)); - break; - case JSON_OBJECT: - options.setResponseFormat(new ChatCompletionsJsonResponseFormat()); - break; - case TEXT: - options.setResponseFormat(new ChatCompletionsTextResponseFormat()); - break; - - default: - throw new SKException( - "Unknown response format: " + promptExecutionSettings.getResponseFormat()); - } - } - - return options; - } - - @Nullable - private static OpenAIToolCallConfig getToolCallConfig( - @Nullable InvocationContext invocationContext, - @Nullable List functions, - List chatRequestMessages, - int requestIndex) { - - if (invocationContext == null || functions == null || functions.isEmpty()) { - return null; - } - - if (invocationContext.getFunctionChoiceBehavior() == null - && invocationContext.getToolCallBehavior() == null) { - return null; - } - - if (invocationContext.getFunctionChoiceBehavior() != null) { - return getFunctionChoiceBehaviorConfig( - invocationContext.getFunctionChoiceBehavior(), - functions, - requestIndex); - } else { - return getToolCallBehaviorConfig( - invocationContext.getToolCallBehavior(), - functions, - chatRequestMessages, - requestIndex); - } - } - - @Nullable - private static OpenAIToolCallConfig getFunctionChoiceBehaviorConfig( - @Nullable FunctionChoiceBehavior functionChoiceBehavior, - @Nullable List functions, - int requestIndex) { - if (functionChoiceBehavior == null) { - return null; - } - - if (functions == null || functions.isEmpty()) { - return null; - } - - ChatCompletionsToolSelection toolChoice; - boolean autoInvoke; - - if (functionChoiceBehavior instanceof RequiredFunctionChoiceBehavior) { - // After first request a required function must have been called already - if (requestIndex >= 1) { - return null; - } - - toolChoice = new ChatCompletionsToolSelection( - ChatCompletionsToolSelectionPreset.REQUIRED); - autoInvoke = ((RequiredFunctionChoiceBehavior) functionChoiceBehavior).isAutoInvoke(); - } else if (functionChoiceBehavior instanceof AutoFunctionChoiceBehavior) { - toolChoice = new ChatCompletionsToolSelection(ChatCompletionsToolSelectionPreset.AUTO); - autoInvoke = ((AutoFunctionChoiceBehavior) functionChoiceBehavior).isAutoInvoke() - && requestIndex < MAXIMUM_INFLIGHT_AUTO_INVOKES; - } else if (functionChoiceBehavior instanceof NoneFunctionChoiceBehavior) { - toolChoice = new ChatCompletionsToolSelection(ChatCompletionsToolSelectionPreset.NONE); - autoInvoke = false; - } else { - throw new SKException( - "Unsupported function choice behavior: " + functionChoiceBehavior); - } - - // List of functions advertised to the model - List toolDefinitions = functions.stream() - .filter(function -> functionChoiceBehavior.isFunctionAllowed(function.getPluginName(), - function.getName())) - .map(OpenAIFunction::getFunctionDefinition) - .map(it -> new ChatCompletionsFunctionToolDefinitionFunction(it.getName()) - .setDescription(it.getDescription()) - .setParameters(it.getParameters())) - .map(ChatCompletionsFunctionToolDefinition::new) - .collect(Collectors.toList()); - - return new OpenAIToolCallConfig( - toolDefinitions, - toolChoice, - autoInvoke, - functionChoiceBehavior.getOptions()); - } - - @Nullable - private static OpenAIToolCallConfig getToolCallBehaviorConfig( - @Nullable ToolCallBehavior toolCallBehavior, - @Nullable List functions, - List chatRequestMessages, - int requestIndex) { - - if (toolCallBehavior == null) { - return null; - } - - if (functions == null || functions.isEmpty()) { - return null; - } - - List toolDefinitions; - ChatCompletionsToolSelection toolChoice; - - // If a specific function is required to be called - if (toolCallBehavior instanceof ToolCallBehavior.RequiredKernelFunction) { - KernelFunction requiredFunction = ((ToolCallBehavior.RequiredKernelFunction) toolCallBehavior) - .getRequiredFunction(); - - String toolChoiceName = String.format("%s%s%s", - requiredFunction.getPluginName(), - OpenAIFunction.getNameSeparator(), - requiredFunction.getName()); - - // If required tool call has already been called dont ask for it again - boolean hasBeenExecuted = hasToolCallBeenExecuted(chatRequestMessages, toolChoiceName); - if (hasBeenExecuted) { - return null; - } - - FunctionDefinition function = OpenAIFunction.toFunctionDefinition( - requiredFunction.getMetadata(), - requiredFunction.getPluginName()); - - toolDefinitions = new ArrayList<>(); - toolDefinitions.add(new ChatCompletionsFunctionToolDefinition( - new ChatCompletionsFunctionToolDefinitionFunction(function.getName()) - .setDescription(function.getDescription()) - .setParameters(function.getParameters()))); - - try { - String json = String.format( - "{\"type\":\"function\",\"function\":{\"name\":\"%s\"}}", toolChoiceName); - - toolChoice = new ChatCompletionsToolSelection( - ChatCompletionsNamedToolSelection.fromJson( - DefaultJsonReader.fromString( - json, - new JsonOptions()))); - } catch (JsonProcessingException e) { - throw SKException.build("Failed to parse tool choice", e); - } catch (IOException e) { - throw new SKException(e); - } - } - // If a set of functions are enabled to be called - else { - toolChoice = new ChatCompletionsToolSelection(ChatCompletionsToolSelectionPreset.AUTO); - - ToolCallBehavior.AllowedKernelFunctions enabledKernelFunctions = (ToolCallBehavior.AllowedKernelFunctions) toolCallBehavior; - toolDefinitions = functions.stream() - .filter(function -> { - // check if all kernel functions are enabled - if (enabledKernelFunctions.isAllKernelFunctionsAllowed()) { - return true; - } - // otherwise, check for the specific function - return enabledKernelFunctions.isFunctionAllowed(function.getPluginName(), - function.getName()); - }) - .map(OpenAIFunction::getFunctionDefinition) - .map(it -> new ChatCompletionsFunctionToolDefinitionFunction(it.getName()) - .setDescription(it.getDescription()) - .setParameters(it.getParameters())) - .map(ChatCompletionsFunctionToolDefinition::new) - .collect(Collectors.toList()); - - if (toolDefinitions.isEmpty()) { - return null; - } - } - - return new OpenAIToolCallConfig( - toolDefinitions, - toolChoice, - toolCallBehavior.isAutoInvokeAllowed() - && requestIndex < Math.min(MAXIMUM_INFLIGHT_AUTO_INVOKES, - toolCallBehavior.getMaximumAutoInvokeAttempts()), - null); - } - - private static boolean hasToolCallBeenExecuted(List chatRequestMessages, - String toolChoiceName) { - return chatRequestMessages - .stream() - .flatMap(message -> { - // Extract tool calls - if (message instanceof ChatRequestAssistantMessage) { - return ((ChatRequestAssistantMessage) message).getToolCalls().stream(); - } - return Stream.empty(); - }) - .filter(toolCall -> { - // Filter if tool call has correct name - if (toolCall instanceof ChatCompletionsFunctionToolCall) { - return ((ChatCompletionsFunctionToolCall) toolCall).getFunction().getName() - .equals(toolChoiceName); - } - return false; - }) - .allMatch(toolcall -> { - String id = toolcall.getId(); - // True if tool call id has a response message - return chatRequestMessages - .stream() - .filter( - chatRequestMessage -> chatRequestMessage instanceof ChatRequestToolMessage) - .anyMatch( - chatRequestMessage -> ((ChatRequestToolMessage) chatRequestMessage) - .getToolCallId() - .equals(id)); - }); - } - - private static List getChatRequestMessages( - List> messages) { - if (messages == null || messages.isEmpty()) { - return new ArrayList<>(); - } - return messages.stream() - .map(OpenAIChatCompletion::getChatRequestMessage) - .collect(Collectors.toList()); - } - - private static List getChatRequestMessages(ChatHistory chatHistory) { - return getChatRequestMessages(chatHistory.getMessages()); - } - - private static ChatRequestMessage getChatRequestMessage( - ChatMessageContent message) { - - AuthorRole authorRole = message.getAuthorRole(); - String content = message.getContent(); - - if (message.getContentType() == ChatMessageContentType.IMAGE_URL && content != null) { - return formImageMessage(message, content); - } - - switch (authorRole) { - case ASSISTANT: - return formAssistantMessage(message, content); - case SYSTEM: - return new ChatRequestSystemMessage(content); - case USER: - return new ChatRequestUserMessage(content); - case TOOL: - String id = null; - - if (message.getMetadata() != null) { - id = message.getMetadata().getId(); - } - - if (id == null) { - throw new SKException( - "Require to create a tool call message, but no tool call id is available"); - } - return new ChatRequestToolMessage(content, id); - default: - LOGGER.debug("Unexpected author role: {}", authorRole); - throw new SKException("Unexpected author role: " + authorRole); - } - } - - private static ChatRequestUserMessage formImageMessage(ChatMessageContent message, - String content) { - ChatMessageImageUrl imageUrl = new ChatMessageImageUrl(content); - if (message instanceof ChatMessageImageContent) { - ChatMessageImageDetailLevel detail = ChatMessageImageDetailLevel.fromString( - ((ChatMessageImageContent) message).getDetail().toString()); - imageUrl.setDetail(detail); - } - - return new ChatRequestUserMessage( - Collections.singletonList(new ChatMessageImageContentItem(imageUrl))); - } - - private static ChatRequestAssistantMessage formAssistantMessage( - ChatMessageContent message, - @Nullable String content) { - // TODO: handle tools other than function calls - ChatRequestAssistantMessage asstMessage = new ChatRequestAssistantMessage(content); - - List toolCalls = FunctionCallContent.getFunctionCalls(message); - - if (toolCalls != null) { - asstMessage.setToolCalls( - toolCalls.stream() - .map(toolCall -> { - KernelArguments arguments = toolCall.getArguments(); - - String args = arguments != null && !arguments.isEmpty() - ? arguments.entrySet().stream() - .map(entry -> String.format("\"%s\": \"%s\"", - StringEscapeUtils.escapeJson(entry.getKey()), - StringEscapeUtils.escapeJson( - entry.getValue().toPromptString()))) - .collect(Collectors.joining(",", "{", "}")) - : "{}"; - - String prefix = ""; - if (toolCall.getPluginName() != null) { - prefix = toolCall.getPluginName() + OpenAIFunction.getNameSeparator(); - } - String name = prefix + toolCall.getFunctionName(); - - FunctionCall fnCall = new FunctionCall(name, args); - return new ChatCompletionsFunctionToolCall(toolCall.getId(), - fnCall); - }) - .collect(Collectors.toList())); - } - return asstMessage; - } - - static ChatRequestMessage getChatRequestMessage( - AuthorRole authorRole, - String content) { - - switch (authorRole) { - case ASSISTANT: - return new ChatRequestAssistantMessage(content); - case SYSTEM: - return new ChatRequestSystemMessage(content); - case USER: - return new ChatRequestUserMessage(content); - case TOOL: - return new ChatRequestToolMessage(content, null); - default: - LOGGER.debug("Unexpected author role: " + authorRole); - throw new SKException("Unexpected author role: " + authorRole); - } - - } - - /** - * Builder for creating a new instance of {@link OpenAIChatCompletion}. - */ - public static class Builder - extends OpenAiServiceBuilder { - - @Override - public OpenAIChatCompletion build() { - - if (this.client == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI client must be provided"); - } - - if (this.modelId == null || modelId.isEmpty()) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI model id must be provided"); - } - - if (deploymentName == null) { - LOGGER.debug("Deployment name is not provided, using model id as deployment name"); - deploymentName = modelId; - } - - return new OpenAIChatCompletion(client, deploymentName, modelId, serviceId); - } - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatMessageContent.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatMessageContent.java deleted file mode 100644 index ed1e28329..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatMessageContent.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.microsoft.semantickernel.contents.FunctionCallContent; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.KernelContent; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -/** - * Represents the content of a chat message. - * - * @param The type of the inner content. - */ -public class OpenAIChatMessageContent extends ChatMessageContent { - - @Deprecated - @Nullable - private final List toolCall; - - /** - * Creates a new instance of the {@link OpenAIChatMessageContent} class. - * - * @param authorRole The author role that generated the content. - * @param content The content. - * @param modelId The model id. - * @param innerContent The inner content. - * @param encoding The encoding. - * @param metadata The metadata. - * @param functionCalls The tool call. - */ - public OpenAIChatMessageContent( - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable T innerContent, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata, - @Nullable List functionCalls) { - super(authorRole, content, (List>) functionCalls, modelId, - innerContent, encoding, metadata); - - if (functionCalls == null) { - this.toolCall = null; - } else { - // Keep OpenAIFunctionToolCall list for legacy - this.toolCall = Collections.unmodifiableList(functionCalls.stream().map(t -> { - if (t instanceof OpenAIFunctionToolCall) { - return (OpenAIFunctionToolCall) t; - } else { - return new OpenAIFunctionToolCall( - t.getId(), - t.getPluginName(), - t.getFunctionName(), - t.getArguments()); - } - }).collect(Collectors.toList())); - } - } - - /** - * Gets any tool calls requested. - * - * @return The tool call. - * - * @deprecated Use {@link FunctionCallContent#getFunctionCalls(ChatMessageContent)} instead. - */ - @Deprecated - @Nullable - public List getToolCall() { - return toolCall; - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatResponse.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatResponse.java deleted file mode 100644 index 6f06af4e0..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatResponse.java +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -/** - * Represents the response from the OpenAI chat completion API. - */ -public interface OpenAIChatResponse { - - /** - * Represents the usage of the chat completion API. - */ - interface Usage { - - /** - * Gets the number of tokens used for the prompt. - * - * @return the number of tokens used for the prompt - */ - @JsonProperty("prompt_tokens") - int getPromptTokens(); - - /** - * Gets the number of tokens used for the completion. - * - * @return the number of tokens used for the completion - */ - @JsonProperty("completion_tokens") - int getCompletionTokens(); - - /** - * Gets the total number of tokens used. - * - * @return the total number of tokens used - */ - @JsonProperty("total_tokens") - int getTotalTokens(); - } - - /** - * Represents a choice in the chat completion response. - */ - interface Choice { - - /** - * Gets the message in the chat completion response. - * - * @return the message in the chat completion response - */ - @JsonProperty("message") - Message getMessage(); - - /** - * Gets the finish details in the chat completion response. - * - * @return the finish details in the chat completion response - */ - @JsonProperty("finish_details") - FinishDetails getFinishDetails(); - - /** - * Gets the index of the choice. - * - * @return the index of the choice - */ - @JsonProperty("index") - int getIndex(); - } - - /** - * Represents a message in the chat completion response. - */ - interface Message { - - /** - * Gets the role of the message. - * - * @return the role of the message - */ - @JsonProperty("role") - String getRole(); - - /** - * Gets the content of the message. - * - * @return the content of the message - */ - @JsonProperty("content") - String getContent(); - } - - /** - * Represents the finish details in the chat completion response. - */ - interface FinishDetails { - - /** - * Gets the type of the finish details. - * - * @return the type of the finish details - */ - @JsonProperty("type") - String getType(); - } - - /** - * Gets the id of the chat completion response. - * - * @return the id of the chat completion response - */ - @JsonProperty("id") - String getId(); - - /** - * Gets the object of the chat completion response. - * - * @return the object of the chat completion response - */ - @JsonProperty("object") - String getObject(); - - /** - * Gets the created time of the chat completion response. - * - * @return the created time of the chat completion response - */ - @JsonProperty("created") - Long getCreated(); - - /** - * Gets the model of the chat completion response. - * - * @return the model of the chat completion response - */ - @JsonProperty("model") - String getModel(); - - /** - * Gets the usage of the chat completion response. - * - * @return the usage of the chat completion response - */ - @JsonProperty("Usage") - List getUsage(); - - /** - * Gets the choices of the chat completion response. - * - * @return the choices of the chat completion response - */ - @JsonProperty("choices") - List getChoices(); - -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java deleted file mode 100644 index cf126d095..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.models.FunctionDefinition; -import com.azure.core.util.BinaryData; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.responseformat.ResponseSchemaGenerator; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata; -import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -class OpenAIFunction { - - private final String pluginName; - private final String name; - private final FunctionDefinition functionDefinition; - - protected OpenAIFunction( - @Nonnull String name, - @Nonnull String pluginName, - @Nonnull FunctionDefinition functionDefinition) { - this.name = name; - this.pluginName = pluginName; - this.functionDefinition = functionDefinition; - } - - public static OpenAIFunction build(KernelFunctionMetadata metadata, String pluginName) { - String name = metadata.getName(); - FunctionDefinition functionDefinition = toFunctionDefinition(metadata, pluginName); - return new OpenAIFunction(name, pluginName, functionDefinition); - } - - public String getName() { - return name; - } - - public String getPluginName() { - return pluginName; - } - - public FunctionDefinition getFunctionDefinition() { - return functionDefinition; - } - - /** - * Gets the separator used between the plugin name and the function name, if a plugin name is - * present. - * - * @return The separator used between the plugin name and the function name. - */ - public static String getNameSeparator() { - return "-"; - } - - /** - * Gets the fully-qualified name of the function. - * - * @return The fully-qualified name of the function. - */ - private static String getFullyQualifiedName( - @Nullable String pluginName, String functionName) { - return (pluginName == null || pluginName.isEmpty()) ? functionName - : pluginName + getNameSeparator() + functionName; - } - - /** - * Converts a KernelFunctionMetadata representation to the SDK's FunctionDefinition - * representation. - * - * @return A FunctionDefinition containing all the function information. - */ - public static FunctionDefinition toFunctionDefinition(KernelFunctionMetadata metadata, - @Nullable String pluginName) { - BinaryData resultParameters; - - Map properties = new HashMap<>(); - List required = new ArrayList<>(); - - try { - ObjectMapper objectMapper = new ObjectMapper(); - for (InputVariable parameter : metadata.getParameters()) { - String parameterJsonSchema = getSchemaForFunctionParameter(parameter); - - properties.put(parameter.getName(), objectMapper.readTree(parameterJsonSchema)); - - if (parameter.isRequired()) { - required.add(parameter.getName()); - } - } - - String json = objectMapper - .writeValueAsString(new OpenAIFunctionParameter("object", required, properties)); - resultParameters = BinaryData.fromObject(objectMapper.readTree(json)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - - FunctionDefinition functionDefinition = new FunctionDefinition( - getFullyQualifiedName(pluginName, metadata.getName())); - functionDefinition.setDescription(metadata.getDescription()); - functionDefinition.setParameters(resultParameters); - - return functionDefinition; - } - - private static class OpenAIFunctionParameter { - - @JsonProperty("type") - private String type; - @JsonProperty("required") - private List required; - @JsonProperty("properties") - private Map properties; - - public OpenAIFunctionParameter( - String type, - List required, - Map properties) { - this.type = type; - this.required = Collections.unmodifiableList(required); - this.properties = Collections.unmodifiableMap(properties); - } - - @SuppressWarnings("UnusedMethod") - public String getType() { - return type; - } - - @SuppressWarnings("UnusedMethod") - public List getRequired() { - return required; - } - - @SuppressWarnings("UnusedMethod") - public Map getProperties() { - return properties; - } - } - - private static String getSchemaForFunctionParameter(@Nullable InputVariable parameter) { - List entries = new ArrayList<>(); - - String type = "string"; - - if (parameter != null && parameter.getType() != null) { - type = getJavaTypeToOpenAiFunctionType(parameter.getType()); - } - - entries.add("\"type\":\"" + type + "\""); - - // Add description if present - String description = null; - if (parameter != null && parameter.getDescription() != null && !parameter.getDescription() - .isEmpty()) { - description = parameter.getDescription(); - description = description.replaceAll("\\r?\\n|\\r", ""); - description = description.replace("\"", "\\\""); - entries.add(String.format("\"description\":\"%s\"", description)); - } - // If custom type, generate schema - if ("object".equalsIgnoreCase(type)) { - return getObjectSchema(parameter.getType(), description); - } - - // Add enum options if parameter is an enum - if (parameter != null && parameter.getEnumValues() != null && !parameter.getEnumValues() - .isEmpty()) { - String enumEntry = parameter - .getEnumValues() - .stream() - .map(Object::toString) - .map(it -> "\"" + it + "\"") - .collect(Collectors.joining(",")); - - entries.add("\"enum\":[ " + enumEntry + " ]"); - } - - String schema = String.join(",", entries); - - return "{" + schema + "}"; - } - - private static String getJavaTypeToOpenAiFunctionType(String javaType) { - switch (javaType.toLowerCase(Locale.ROOT)) { - case "java.lang.boolean": - case "boolean": - return "boolean"; - case "java.lang.integer": - case "integer": - case "int": - case "java.lang.long": - case "long": - case "java.lang.short": - case "short": - case "java.lang.byte": - case "byte": - return "integer"; - case "java.lang.double": - case "double": - case "java.lang.float": - case "float": - return "number"; - case "java.lang.string": - case "string": - return "string"; - case "array": - return "array"; - case "java.lang.void": - case "void": - return "null"; - default: - return "object"; - } - } - - private static String getObjectSchema(String type, String description) { - String schema = "{ \"type\" : \"object\" }"; - try { - Class clazz = Class.forName(type); - schema = ResponseSchemaGenerator.jacksonGenerator().generateSchema(clazz); - - } catch (ClassNotFoundException | SKException ignored) { - - } - Map properties = BinaryData.fromString(schema).toObject(Map.class); - if (StringUtils.isNotBlank(description)) { - properties.put("description", description); - } - return BinaryData.fromObject(properties).toString(); - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunctionToolCall.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunctionToolCall.java deleted file mode 100644 index c1def3379..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunctionToolCall.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.microsoft.semantickernel.contents.FunctionCallContent; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; - -/** - * Represents a call to a function in the OpenAI tool. - * - * @deprecated Use {@link FunctionCallContent} instead. - */ -@Deprecated -public class OpenAIFunctionToolCall extends FunctionCallContent { - - /** - * Creates a new instance of the {@link OpenAIFunctionToolCall} class. - * - * @param id The ID of the tool call. - * @param pluginName The name of the plugin with which this function is associated, if any. - * @param functionName The name of the function. - * @param arguments A name/value collection of the arguments to the function, if any. - */ - public OpenAIFunctionToolCall( - @Nullable String id, - @Nullable String pluginName, - String functionName, - @Nullable KernelArguments arguments) { - super(functionName, pluginName, id, arguments); - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIStreamingChatMessageContent.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIStreamingChatMessageContent.java deleted file mode 100644 index c919f5c6e..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIStreamingChatMessageContent.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.StreamingChatContent; -import java.nio.charset.Charset; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Represents the content of a chat message. - * - * @param The type of the inner content. - */ -public class OpenAIStreamingChatMessageContent extends OpenAIChatMessageContent implements - StreamingChatContent { - - private final String id; - - /** - * Creates a new instance of the {@link OpenAIChatMessageContent} class. - * - * @param id The id of the message. - * @param authorRole The author role that generated the content. - * @param content The content. - * @param modelId The model id. - * @param innerContent The inner content. - * @param encoding The encoding. - * @param metadata The metadata. - * @param toolCall The tool call. - */ - public OpenAIStreamingChatMessageContent( - String id, - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable T innerContent, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata, - @Nullable List toolCall) { - super( - authorRole, - content, - modelId, - innerContent, - encoding, - metadata, - toolCall); - - this.id = id; - } - - @Override - public String getId() { - return id; - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIToolCallConfig.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIToolCallConfig.java deleted file mode 100644 index 454ed3ce1..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIToolCallConfig.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.models.ChatCompletionsToolDefinition; -import com.azure.ai.openai.models.ChatCompletionsToolSelection; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehaviorOptions; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.List; - -public class OpenAIToolCallConfig { - private final List tools; - private final ChatCompletionsToolSelection toolChoice; - private final boolean autoInvoke; - @Nullable - private final FunctionChoiceBehaviorOptions options; - - /** - * Creates a new instance of the {@link OpenAIToolCallConfig} class. - * - * @param tools The list of tools available for the call. - * @param toolChoice The tool selection strategy. - * @param autoInvoke Indicates whether to automatically invoke the tool. - * @param options Additional options for function choice behavior. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public OpenAIToolCallConfig( - List tools, - ChatCompletionsToolSelection toolChoice, - boolean autoInvoke, - @Nullable FunctionChoiceBehaviorOptions options) { - this.tools = tools; - this.toolChoice = toolChoice; - this.autoInvoke = autoInvoke; - this.options = options; - } - - /** - * Gets the list of tools available for the call. - * - * @return The list of tools. - */ - public List getTools() { - return Collections.unmodifiableList(tools); - } - - /** - * Gets the tool selection strategy. - * - * @return The tool selection strategy. - */ - public ChatCompletionsToolSelection getToolChoice() { - return toolChoice; - } - - /** - * Indicates whether to automatically invoke the tool. - * - * @return True if auto-invocation is enabled; otherwise, false. - */ - public boolean isAutoInvoke() { - return autoInvoke; - } - - /** - * Gets additional options for function choice behavior. - * - * @return The function choice behavior options. - */ - public FunctionChoiceBehaviorOptions getOptions() { - return options; - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiXMLPromptParser.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiXMLPromptParser.java deleted file mode 100644 index 4f5fd99cc..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiXMLPromptParser.java +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.models.ChatRequestAssistantMessage; -import com.azure.ai.openai.models.ChatRequestFunctionMessage; -import com.azure.ai.openai.models.ChatRequestMessage; -import com.azure.ai.openai.models.ChatRequestSystemMessage; -import com.azure.ai.openai.models.ChatRequestToolMessage; -import com.azure.ai.openai.models.ChatRequestUserMessage; -import com.azure.ai.openai.models.FunctionDefinition; -import com.azure.core.util.BinaryData; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.implementation.chatcompletion.ChatPromptParseVisitor; -import com.microsoft.semantickernel.implementation.chatcompletion.ChatXMLPromptParser; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class OpenAiXMLPromptParser { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAiXMLPromptParser.class); - - private static class OpenAiChatPromptParseVisitor implements - ChatPromptParseVisitor { - - @Nullable - private ParsedPrompt parsedRaw = null; - private final List functionDefinitions = new ArrayList<>(); - private final List messages = new ArrayList<>(); - - @Override - public ChatPromptParseVisitor addMessage(String role, - String content) { - messages.add(getChatRequestMessage(role, content)); - return this; - } - - @Override - public ChatPromptParseVisitor addFunction( - String name, - @Nullable String description, - @Nullable BinaryData parameters) { - FunctionDefinition function = new FunctionDefinition(name); - - if (description != null) { - function.setDescription(description); - } - - if (parameters != null) { - function.setParameters(parameters); - } - - functionDefinitions.add(function); - - return this; - } - - @Override - public boolean areMessagesEmpty() { - return messages.isEmpty(); - } - - @Override - public ChatPromptParseVisitor fromRawPrompt(String rawPrompt) { - ChatRequestUserMessage message = new ChatRequestUserMessage(rawPrompt); - - if (message.getName() == null) { - message.setName(UUID.randomUUID().toString()); - } - - this.parsedRaw = new ParsedPrompt(Collections.singletonList(message), null); - return this; - } - - @Override - public ParsedPrompt get() { - if (parsedRaw != null) { - return parsedRaw; - } - - return new ParsedPrompt(messages, functionDefinitions); - } - - @Override - public ChatPromptParseVisitor reset() { - return new OpenAiChatPromptParseVisitor(); - } - } - - public static ParsedPrompt parse(String rawPrompt) { - ChatPromptParseVisitor visitor = ChatXMLPromptParser.parse(rawPrompt, - new OpenAiChatPromptParseVisitor()); - - return visitor.get(); - - } - - private static ChatRequestMessage getChatRequestMessage( - String role, - String content) { - try { - AuthorRole authorRole = AuthorRole.valueOf(role.toUpperCase(Locale.ROOT)); - return OpenAIChatCompletion.getChatRequestMessage(authorRole, content); - } catch (IllegalArgumentException e) { - LOGGER.debug("Unknown author role: " + role); - throw new SKException("Unknown author role: " + role); - } - } - - public static ChatRequestMessage unescapeRequest(ChatRequestMessage message) { - if (message instanceof ChatRequestUserMessage) { - ChatRequestUserMessage chatRequestMessage = (ChatRequestUserMessage) message; - String content = StringEscapeUtils.unescapeXml( - BinaryDataUtils.toString(chatRequestMessage.getContent())); - - return new ChatRequestUserMessage(content) - .setName(chatRequestMessage.getName()); - } else if (message instanceof ChatRequestSystemMessage) { - ChatRequestSystemMessage chatRequestMessage = (ChatRequestSystemMessage) message; - String content = StringEscapeUtils - .unescapeXml( - BinaryDataUtils.toString(chatRequestMessage.getContent())); - - return new ChatRequestSystemMessage(content) - .setName(chatRequestMessage.getName()); - } else if (message instanceof ChatRequestAssistantMessage) { - ChatRequestAssistantMessage chatRequestMessage = (ChatRequestAssistantMessage) message; - String content = StringEscapeUtils - .unescapeXml( - BinaryDataUtils.toString(chatRequestMessage.getContent())); - - return new ChatRequestAssistantMessage(content) - .setToolCalls(chatRequestMessage.getToolCalls()) - .setFunctionCall(chatRequestMessage.getFunctionCall()) - .setName(chatRequestMessage.getName()); - } else if (message instanceof ChatRequestFunctionMessage) { - ChatRequestFunctionMessage chatRequestMessage = (ChatRequestFunctionMessage) message; - String content = StringEscapeUtils.unescapeXml(chatRequestMessage.getContent()); - - return new ChatRequestFunctionMessage( - chatRequestMessage.getName(), - content); - } else if (message instanceof ChatRequestToolMessage) { - ChatRequestToolMessage chatRequestMessage = (ChatRequestToolMessage) message; - String content = StringEscapeUtils - .unescapeXml( - BinaryDataUtils.toString(chatRequestMessage.getContent())); - - return new ChatRequestToolMessage( - content, - chatRequestMessage.getToolCallId()); - } - - throw new SKException("Unknown message type: " + message.getClass().getSimpleName()); - } -} \ No newline at end of file diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/ParsedPrompt.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/ParsedPrompt.java deleted file mode 100644 index 7f49573ee..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/ParsedPrompt.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.models.ChatRequestMessage; -import com.azure.ai.openai.models.FunctionDefinition; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; - -class ParsedPrompt { - - private final List chatRequestMessages; - private final List functions; - - protected ParsedPrompt(List parsedMessages, - @Nullable List parsedFunctions) { - this.chatRequestMessages = parsedMessages; - if (parsedFunctions == null) { - parsedFunctions = new ArrayList<>(); - } - this.functions = parsedFunctions; - } - - public List getChatRequestMessages() { - return chatRequestMessages; - } - - public List getFunctions() { - return functions; - } -} \ No newline at end of file diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/ChatCompletionsJsonSchemaResponseFormat.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/ChatCompletionsJsonSchemaResponseFormat.java deleted file mode 100644 index f5a3b1c4f..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/ChatCompletionsJsonSchemaResponseFormat.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat; - -import com.azure.ai.openai.models.ChatCompletionsResponseFormat; -import com.azure.json.JsonWriter; -import com.microsoft.semantickernel.orchestration.responseformat.JsonResponseSchema; -import java.io.IOException; - -/** - * Represents a response format for chat completions that uses a JSON schema. - */ -public class ChatCompletionsJsonSchemaResponseFormat extends ChatCompletionsResponseFormat { - - private final JsonResponseSchema schema; - private String type = "json_schema"; - - /** - * Creates a new instance of the {@link ChatCompletionsJsonSchemaResponseFormat} class. - * - * @param schema The JSON schema. - */ - public ChatCompletionsJsonSchemaResponseFormat(JsonResponseSchema schema) { - this.schema = schema; - } - - @Override - public String getType() { - return this.type; - } - - @Override - public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { - jsonWriter.writeStartObject(); - jsonWriter.writeStringField("type", this.type); - jsonWriter.writeStartObject("json_schema"); - - jsonWriter.writeBooleanField("strict", this.schema.isStrict()); - jsonWriter.writeStringField("name", this.schema.getName()); - - jsonWriter.writeRawField("schema", this.schema.getSchema()); - jsonWriter.writeEndObject(); - return jsonWriter.writeEndObject(); - } - -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/JacksonResponseFormatGenerator.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/JacksonResponseFormatGenerator.java deleted file mode 100644 index 97060cab0..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/responseformat/JacksonResponseFormatGenerator.java +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ContainerNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.victools.jsonschema.generator.OptionPreset; -import com.github.victools.jsonschema.generator.SchemaGenerator; -import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; -import com.github.victools.jsonschema.generator.SchemaVersion; -import com.github.victools.jsonschema.module.jackson.JacksonModule; -import com.microsoft.semantickernel.orchestration.responseformat.ResponseSchemaGenerator; - -/** - * Represents a response format generator that uses Jackson. - */ -public class JacksonResponseFormatGenerator implements ResponseSchemaGenerator { - - private final SchemaGenerator generator; - - /** - * Creates a new instance of the {@link JacksonResponseFormatGenerator} class. - */ - public JacksonResponseFormatGenerator() { - JacksonModule module = new JacksonModule(); - SchemaGeneratorConfigBuilder builder = new SchemaGeneratorConfigBuilder( - SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON) - .with(module); - - builder - .forFields() - .withRequiredCheck(fieldScope -> { - return true; - }); - - generator = new SchemaGenerator(builder.build()); - } - - /** - * Creates a new instance of the {@link JacksonResponseFormatGenerator} class. - * - * @param generator The schema generator. - */ - public JacksonResponseFormatGenerator(SchemaGenerator generator) { - this.generator = generator; - } - - @Override - public String generateSchema(Class clazz) { - ObjectNode schema = generator.generateSchema(clazz); - - sanitize(schema); - - return schema.toPrettyString(); - } - - private static void sanitize(ContainerNode schema) { - if (schema instanceof ObjectNode) { - ((ObjectNode) schema).remove("$schema"); - - if (schema.has("type") && schema.get("type").asText().equals("object")) { - ((ObjectNode) schema).put("additionalProperties", false); - } - - for (JsonNode node : (ObjectNode) schema) { - if (node instanceof ContainerNode) { - sanitize((ContainerNode) node); - } - } - } else if (schema instanceof ArrayNode) { - for (JsonNode node : (ArrayNode) schema) { - if (node instanceof ContainerNode) { - sanitize((ContainerNode) node); - } - } - } - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/implementation/OpenAIRequestSettings.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/implementation/OpenAIRequestSettings.java deleted file mode 100644 index 35d0d3f3e..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/implementation/OpenAIRequestSettings.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.implementation; - -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.policy.UserAgentPolicy; -import com.azure.core.http.rest.RequestOptions; -import com.azure.core.util.Context; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; -import org.slf4j.Logger; - -/** - * Provides Http request settings for OpenAI requests. - */ -public final class OpenAIRequestSettings { - - private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger( - OpenAIRequestSettings.class); - - private static final String SEMANTIC_KERNEL_VERSION_PROPERTY_NAME = "semantic-kernel.version"; - private static final String SEMANTIC_KERNEL_VERSION_PROPERTIES_FILE = "semantic-kernel-version.properties"; - - private static final String useragent; - private static final String header; - - public static final String SEMANTIC_KERNEL_DISABLE_USERAGENT_PROPERTY = "semantic-kernel.useragent-disable"; - - private static final boolean disabled; - - static { - disabled = isDisabled(); - String version = loadVersion(); - useragent = "semantic-kernel-java/" + version; - header = "java/" + version; - } - - private static boolean isDisabled() { - return Boolean.parseBoolean( - System.getProperty(SEMANTIC_KERNEL_DISABLE_USERAGENT_PROPERTY, "false")); - } - - private static String loadVersion() { - - String version = "unknown"; - - try (InputStream settingsFile = OpenAIRequestSettings.class.getResourceAsStream( - SEMANTIC_KERNEL_VERSION_PROPERTIES_FILE)) { - - Properties props = new Properties(); - props.load(settingsFile); - if (props.containsKey(SEMANTIC_KERNEL_VERSION_PROPERTY_NAME)) { - String skVersion = props.getProperty(SEMANTIC_KERNEL_VERSION_PROPERTY_NAME); - if (skVersion != null && !skVersion.isEmpty()) { - return skVersion; - } - } - } catch (IOException e) { - //Ignore - LOGGER.trace("Failed to load Semantic Kernel version from properties file", e); - } - return version; - } - - /** - * Get the HTTP request options for OpenAI requests. - * - * @return The request options - */ - public static RequestOptions getRequestOptions() { - RequestOptions requestOptions = new RequestOptions(); - - if (disabled) { - return requestOptions; - } - - return requestOptions - .setHeader(HttpHeaderName.fromString("Semantic-Kernel-Version"), header) - .setContext(new Context(UserAgentPolicy.APPEND_USER_AGENT_CONTEXT_KEY, useragent)); - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAIStreamingTextContent.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAIStreamingTextContent.java deleted file mode 100644 index 13272fb50..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAIStreamingTextContent.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.textcompletion; - -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.textcompletion.TextContent; - -import javax.annotation.Nullable; - -/** - * StreamingTextContent is a wrapper for TextContent that allows for streaming. - */ -public class OpenAIStreamingTextContent extends StreamingTextContent { - - /** - * Initializes a new instance of the {@code StreamingTextContent} class with a provided text - * content. - * - * @param content The text content. - */ - public OpenAIStreamingTextContent(TextContent content) { - super(content, 0, null, null); - } - - @Override - @Nullable - public String getContent() { - TextContent content = getInnerContent(); - if (content == null) { - return null; - } - return content.getContent(); - } - -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAITextGenerationService.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAITextGenerationService.java deleted file mode 100644 index ec04c568d..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textcompletion/OpenAITextGenerationService.java +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.textcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.CompletionsOptions; -import com.azure.ai.openai.models.CompletionsUsage; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.OpenAiService; -import com.microsoft.semantickernel.aiservices.openai.implementation.OpenAIRequestSettings; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.textcompletion.TextContent; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * An OpenAI implementation of a {@link TextGenerationService}. - */ -public class OpenAITextGenerationService extends OpenAiService - implements TextGenerationService { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAITextGenerationService.class); - - /** - * Creates a new {@link OpenAITextGenerationService}. - * - * @param client OpenAI client - * @param modelId OpenAI model id - * @param serviceId Service id - */ - protected OpenAITextGenerationService( - OpenAIAsyncClient client, - String modelId, - @Nullable String serviceId, - String deploymentName) { - super(client, serviceId, modelId, deploymentName); - } - - /** - * Creates a builder for creating a {@link OpenAITextGenerationService}. - * - * @return A new {@link OpenAITextGenerationService} builder. - */ - public static Builder builder() { - return new Builder(); - } - - @Override - public Mono> getTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel) { - return this.internalCompleteTextAsync(prompt, executionSettings); - } - - @Override - public Flux getStreamingTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel) { - return this - .internalCompleteTextAsync(prompt, executionSettings) - .flatMapMany(it -> Flux.fromStream(it.stream()) - .map(OpenAIStreamingTextContent::new)); - } - - protected Mono> internalCompleteTextAsync( - String text, - @Nullable PromptExecutionSettings requestSettings) { - - CompletionsOptions completionsOptions = getCompletionsOptions(text, requestSettings); - - return getClient() - .getCompletionsWithResponse(getDeploymentName(), completionsOptions, - OpenAIRequestSettings.getRequestOptions()) - .flatMap(completionsResult -> { - if (completionsResult.getStatusCode() >= 400) { - return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR, - "Request failed: " + completionsResult.getStatusCode())); - } - return Mono.just(completionsResult.getValue()); - }) - .map(completions -> { - FunctionResultMetadata metadata = FunctionResultMetadata.build( - completions.getId(), - completions.getUsage(), - completions.getCreatedAt()); - - return completions - .getChoices() - .stream() - .map(choice -> { - return new TextContent( - choice.getText(), - completionsOptions.getModel(), - metadata); - }) - .collect(Collectors.toList()); - }); - } - - private CompletionsOptions getCompletionsOptions( - String text, - @Nullable PromptExecutionSettings requestSettings) { - text = StringEscapeUtils.unescapeXml(text); - - if (requestSettings == null) { - return new CompletionsOptions(Collections.singletonList(text)) - .setMaxTokens(PromptExecutionSettings.DEFAULT_MAX_TOKENS); - } - if (requestSettings.getMaxTokens() < 1) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, "Max tokens must be >0"); - } - if (requestSettings.getResultsPerPrompt() < 1 - || requestSettings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - String.format("Results per prompt must be in range between 1 and %d, inclusive.", - MAX_RESULTS_PER_PROMPT)); - } - - CompletionsOptions options = new CompletionsOptions(Collections.singletonList(text)) - .setMaxTokens(requestSettings.getMaxTokens()) - .setTemperature(requestSettings.getTemperature()) - .setTopP(requestSettings.getTopP()) - .setFrequencyPenalty(requestSettings.getFrequencyPenalty()) - .setPresencePenalty(requestSettings.getPresencePenalty()) - .setModel(getModelId()) - .setN(requestSettings.getResultsPerPrompt()) - .setUser(requestSettings.getUser()) - .setBestOf(requestSettings.getBestOf()) - .setLogitBias(new HashMap<>()); - return options; - } - - /** - * Builder for a TextGenerationService - */ - public static class Builder extends TextGenerationService.Builder { - - @Override - public TextGenerationService build() { - - if (this.client == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI client must be provided"); - } - if (this.modelId == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI model id must be provided"); - } - if (deploymentName == null) { - LOGGER.debug("Deployment name is not provided, using model id as deployment name"); - deploymentName = modelId; - } - - return new OpenAITextGenerationService( - this.client, - this.modelId, - this.serviceId, - this.deploymentName); - } - } -} diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textembedding/OpenAITextEmbeddingGenerationService.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textembedding/OpenAITextEmbeddingGenerationService.java deleted file mode 100644 index 355f2ab95..000000000 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/textembedding/OpenAITextEmbeddingGenerationService.java +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.textembedding; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.EmbeddingItem; -import com.azure.ai.openai.models.Embeddings; -import com.azure.ai.openai.models.EmbeddingsOptions; -import com.microsoft.semantickernel.aiservices.openai.OpenAiService; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder; -import com.microsoft.semantickernel.services.textembedding.Embedding; -import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -/** - * An OpenAI implementation of a {@link TextEmbeddingGenerationService}. - */ -public class OpenAITextEmbeddingGenerationService extends OpenAiService - implements TextEmbeddingGenerationService { - - private static final Logger LOGGER = LoggerFactory - .getLogger(OpenAITextEmbeddingGenerationService.class); - private final int dimensions; - - /** - * Dimension of the OpenAI - * {@code text-embedding-3-small} model. - */ - public static final int EMBEDDING_DIMENSIONS_SMALL = 1536; - /** - * Dimension of the OpenAI - * {@code text-embedding-3-large} model. - */ - public static final int EMBEDDING_DIMENSIONS_LARGE = 3072; - - /** - * Creates a new {@link OpenAITextEmbeddingGenerationService}. - * - * @param client OpenAI client - * @param deploymentName deployment name - * @param dimensions The dimensions for the embeddings. - * @param modelId OpenAI model id - * @param serviceId Service id - */ - public OpenAITextEmbeddingGenerationService( - OpenAIAsyncClient client, - String deploymentName, - String modelId, - @Nullable String serviceId, - int dimensions) { - super(client, serviceId, modelId, deploymentName); - this.dimensions = dimensions; - } - - /** - * Creates a builder for creating a {@link OpenAITextEmbeddingGenerationService}. - * - * @return A new {@link OpenAITextEmbeddingGenerationService} builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Generates embeddings for the given data. - * - * @param data The data to generate embeddings for. - * @return A Mono that completes with the embeddings. - */ - @Override - public Mono generateEmbeddingAsync(String data) { - return this.internalGenerateTextEmbeddingsAsync(Arrays.asList(data)) - .flatMap(embeddings -> { - if (embeddings.isEmpty()) { - return Mono.empty(); - } - - return Mono.just(embeddings.get(0)); - }); - } - - /** - * Generates embeddings for the given data. - * - * @param data The data to generate embeddings for. - * @return A Mono that completes with the embeddings. - */ - @Override - public Mono> generateEmbeddingsAsync(List data) { - return this.internalGenerateTextEmbeddingsAsync(data); - } - - protected Mono> internalGenerateTextEmbeddingsAsync(List data) { - EmbeddingsOptions options = new EmbeddingsOptions(data) - .setModel(getModelId()) - .setInputType("string"); - if (dimensions > 0) { - options.setDimensions(dimensions); - } - - return getClient() - .getEmbeddings(getModelId(), options) - .flatMapIterable(Embeddings::getData) - .mapNotNull(EmbeddingItem::getEmbedding) - .map(ArrayList::new) - .mapNotNull(Embedding::new) - .collectList(); - } - - /** - * A builder for creating a {@link OpenAITextEmbeddingGenerationService}. - */ - public static class Builder extends - OpenAiServiceBuilder { - - private int dimensions = -1; - - /** - * Sets the dimensions for the embeddings. - * - * @param dimensions The dimensions for the embeddings. - * @return The builder. - */ - public Builder withDimensions(int dimensions) { - this.dimensions = dimensions; - return this; - } - - @Override - public OpenAITextEmbeddingGenerationService build() { - if (this.client == null) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI client must be provided"); - } - - if (this.modelId == null || modelId.isEmpty()) { - throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, - "OpenAI model id must be provided"); - } - - if (deploymentName == null) { - LOGGER.debug("Deployment name is not provided, using model id as deployment name"); - deploymentName = modelId; - } - - return new OpenAITextEmbeddingGenerationService(client, deploymentName, modelId, - serviceId, dimensions); - } - } -} diff --git a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.AudioToTextService$Builder b/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.AudioToTextService$Builder deleted file mode 100644 index 439003dbe..000000000 --- a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.AudioToTextService$Builder +++ /dev/null @@ -1 +0,0 @@ -com.microsoft.semantickernel.aiservices.openai.audio.OpenAiAudioToTextService$Builder \ No newline at end of file diff --git a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.TextToAudioService$Builder b/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.TextToAudioService$Builder deleted file mode 100644 index 7d494cbb2..000000000 --- a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.audio.TextToAudioService$Builder +++ /dev/null @@ -1 +0,0 @@ -com.microsoft.semantickernel.aiservices.openai.audio.OpenAiTextToAudioService$Builder \ No newline at end of file diff --git a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService$Builder b/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService$Builder deleted file mode 100644 index ba94ee72f..000000000 --- a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService$Builder +++ /dev/null @@ -1 +0,0 @@ -com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion$Builder diff --git a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.textcompletion.TextGenerationService$Builder b/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.textcompletion.TextGenerationService$Builder deleted file mode 100644 index 6012c79d3..000000000 --- a/aiservices/openai/src/main/resources/META-INF/services/com.microsoft.semantickernel.services.textcompletion.TextGenerationService$Builder +++ /dev/null @@ -1 +0,0 @@ -com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService$Builder diff --git a/aiservices/openai/src/main/resources/com/microsoft/semantickernel/aiservices/openai/implementation/semantic-kernel-version.properties b/aiservices/openai/src/main/resources/com/microsoft/semantickernel/aiservices/openai/implementation/semantic-kernel-version.properties deleted file mode 100644 index 73220f4f8..000000000 --- a/aiservices/openai/src/main/resources/com/microsoft/semantickernel/aiservices/openai/implementation/semantic-kernel-version.properties +++ /dev/null @@ -1 +0,0 @@ -semantic-kernel.version=${project.version} \ No newline at end of file diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/OtelCaptureTest.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/OtelCaptureTest.java deleted file mode 100644 index 5c3444b3a..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/OtelCaptureTest.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.ChatCompletions; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.Completions; -import com.azure.ai.openai.models.CompletionsOptions; -import com.azure.ai.openai.models.CompletionsUsage; -import com.azure.core.http.rest.Response; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.ArrayList; -import java.util.Collection; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import reactor.core.publisher.Mono; - -public class OtelCaptureTest { - - private static OpenTelemetrySdk otel; - private static ArrayList spans = new ArrayList<>(); - - @BeforeEach - public void clearSpans() { - spans.clear(); - } - - @BeforeAll - public static void setup() { - - SdkTracerProvider tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.builder(new SpanExporter() { - @Override - public CompletableResultCode export(Collection collection) { - spans.addAll(collection); - return new CompletableResultCode(); - } - - @Override - public CompletableResultCode flush() { - return new CompletableResultCode(); - } - - @Override - public CompletableResultCode shutdown() { - return new CompletableResultCode(); - } - }) - .build()) - .build(); - - GlobalOpenTelemetry.resetForTest(); - - otel = OpenTelemetrySdk.builder() - .setTracerProvider(tracerProvider) - .buildAndRegisterGlobal(); - } - - @AfterAll - public static void shutdown() { - otel.shutdown(); - } - - @Test - public void otelChatCaptureTest() { - OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class); - - CompletionsUsage completionsUsage = Mockito.mock(CompletionsUsage.class); - Mockito.when(completionsUsage.getCompletionTokens()).thenReturn(21); - Mockito.when(completionsUsage.getPromptTokens()).thenReturn(42); - - ChatCompletions chatCompletions = Mockito.mock(ChatCompletions.class); - Mockito.when(chatCompletions.getUsage()).thenReturn(completionsUsage); - - Response response = Mockito.mock(Response.class); - Mockito.when(response.getStatusCode()).thenReturn(200); - Mockito.when(response.getValue()).thenReturn(chatCompletions); - - Mockito.when(openAIAsyncClient.getChatCompletionsWithResponse( - Mockito.any(), - Mockito.any(), - Mockito.any())).thenAnswer(invocation -> Mono.just(response)); - - OpenAIChatCompletion client = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(openAIAsyncClient) - .withModelId("a-model") - .build(); - - try { - client.getChatMessageContentsAsync( - "foo", - null, - null).block(); - } catch (Exception e) { - // Expect to fail - } - - Assertions.assertFalse(spans.isEmpty()); - Assertions.assertEquals("a-model", - spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.request.model"))); - Assertions.assertEquals("chat.completions", - spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.operation.name"))); - Assertions.assertEquals("openai", - spans.get(0).getAttributes().get(AttributeKey.stringKey("gen_ai.system"))); - Assertions.assertEquals(21, - spans.get(0).getAttributes() - .get(AttributeKey.longKey("gen_ai.usage.output_tokens"))); - Assertions.assertEquals(42, - spans.get(0).getAttributes() - .get(AttributeKey.longKey("gen_ai.usage.input_tokens"))); - } -} diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Bar.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Bar.java deleted file mode 100644 index 45d1caa78..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Bar.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Bar { - - private final String bar; - - public Bar( - @JsonProperty("bar") String bar) { - this.bar = bar; - } - - public String getBar() { - return bar; - } - -} diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Baz.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Baz.java deleted file mode 100644 index 90ad60ac1..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Baz.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Baz { - - @JsonProperty("bar") - private final Bar bar; - - @JsonCreator - public Baz( - @JsonProperty("bar") Bar bar) { - this.bar = bar; - } - - @JsonProperty("bar") - public Bar getBar() { - return bar; - } -} \ No newline at end of file diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Foo.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Foo.java deleted file mode 100644 index 34479b221..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/Foo.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Foo { - - @JsonProperty("bar") - private final T bar; - - @JsonCreator - public Foo( - @JsonProperty("bar") T bar) { - this.bar = bar; - } - - @JsonProperty("bar") - public T getBar() { - return bar; - } -} \ No newline at end of file diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/JsonSchemaTest.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/JsonSchemaTest.java deleted file mode 100644 index 33870fba2..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/JsonSchemaTest.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -public class JsonSchemaTest { - - @Test - public void jacksonGenerationTest() throws JsonProcessingException { - JsonSchemaResponseFormat format = JsonSchemaResponseFormat.builder() - .setResponseFormat(Foo.class) - .setName("foo") - .build(); - - Assertions.assertEquals("foo", format.getJsonSchema().getName()); - - Assertions.assertTrue(format.getJsonSchema().getSchema() - .replaceAll("\\r\\n|\\r|\\n", "") - .replaceAll(" +", "") - .contains( - "\"type\":\"object\",\"properties\":{\"bar\":{}}")); - } - - @Test - public void openAIFunctionTest() { - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new TestPlugin(), - "test"); - - Assertions.assertNotNull(plugin); - Assertions.assertEquals(plugin.getName(), "test"); - Assertions.assertEquals(plugin.getFunctions().size(), 3); - - KernelFunction testFunction = plugin.getFunctions() - .get("asyncPersonFunction"); - OpenAIFunction openAIFunction = OpenAIFunction.build( - testFunction.getMetadata(), - plugin.getName()); - - String parameters = "{\"type\":\"object\",\"required\":[\"person\",\"input\"],\"properties\":{\"input\":{\"type\":\"string\",\"description\":\"input string\"},\"person\":{\"type\":\"object\",\"properties\":{\"age\":{\"type\":\"integer\",\"description\":\"The age of the person.\"},\"name\":{\"type\":\"string\",\"description\":\"The name of the person.\"},\"title\":{\"type\":\"string\",\"enum\":[\"MS\",\"MRS\",\"MR\"],\"description\":\"The title of the person.\"}},\"required\":[\"age\",\"name\",\"title\"],\"additionalProperties\":false,\"description\":\"input person\"}}}"; - Assertions.assertEquals(parameters, - openAIFunction.getFunctionDefinition().getParameters().toString()); - - } - - public static class TestPlugin { - - @DefineKernelFunction - public String testFunction( - @KernelFunctionParameter(name = "input", description = "input string") String input) { - return "test" + input; - } - - @DefineKernelFunction(returnType = "int") - public Mono asyncTestFunction( - @KernelFunctionParameter(name = "input") String input) { - return Mono.just(1); - } - - @DefineKernelFunction(returnType = "int", description = "test function description", name = "asyncPersonFunction", returnDescription = "test return description") - public Mono asyncPersonFunction( - @KernelFunctionParameter(name = "person", description = "input person", type = Person.class) Person person, - @KernelFunctionParameter(name = "input", description = "input string") String input) { - return Mono.just(1); - } - } - - private static enum Title { - MS, MRS, MR - } - - public static class Person { - @JsonPropertyDescription("The name of the person.") - private String name; - @JsonPropertyDescription("The age of the person.") - private int age; - @JsonPropertyDescription("The title of the person.") - private Title title; - - public Person(String name, int age) { - this.name = name; - this.age = age; - } - - public String getName() { - return name; - } - - public int getAge() { - return age; - } - - public Title getTitle() { - return title; - } - - public void setTitle(Title title) { - this.title = title; - } - } - -} diff --git a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiChatCompletionTest.java b/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiChatCompletionTest.java deleted file mode 100644 index 5a1be82a4..000000000 --- a/aiservices/openai/src/test/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAiChatCompletionTest.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.aiservices.openai.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.ChatCompletions; -import com.azure.ai.openai.models.ChatCompletionsFunctionToolCall; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.ChatRequestAssistantMessage; -import com.azure.core.http.HttpHeaders; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.rest.Response; -import com.azure.json.JsonOptions; -import com.azure.json.implementation.DefaultJsonReader; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.nio.charset.Charset; -import java.util.Arrays; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import reactor.core.publisher.Mono; - -public class OpenAiChatCompletionTest { - - @Test - public void serializesToolCallsCorrectly() { - OpenAIAsyncClient client = Mockito.mock(OpenAIAsyncClient.class); - OpenAIChatCompletion chatCompletion = mockClient(client); - - ChatHistory chatHistory = new ChatHistory(); - - chatHistory.addUserMessage( - "What is the name of the pet with id ca2fc6bc-1307-4da6-a009-d7bf88dec37b?"); - - chatHistory.addMessage(new OpenAIChatMessageContent( - AuthorRole.ASSISTANT, - "", - "test", - null, - Charset.defaultCharset(), - null, - Arrays.asList( - new OpenAIFunctionToolCall( - "a-tool-id", - "pluginName", - "funcName", - KernelArguments.builder() - .withVariable("id", "ca2fc6bc-1307-4da6-a009-d7bf88dec37b") - .build())))); - chatHistory.addMessage(new OpenAIChatMessageContent( - AuthorRole.TOOL, - "Snuggles", - "test", - null, - Charset.defaultCharset(), - FunctionResultMetadata.build("a-tool-id"), - null)); - - chatCompletion - .getChatMessageContentsAsync(chatHistory, null, null).block(); - - Mockito.verify(client, Mockito.times(1)) - .getChatCompletionsWithResponse( - Mockito.any(), - Mockito.argThat(options -> { - ChatRequestAssistantMessage message = ((ChatRequestAssistantMessage) options - .getMessages() - .get(1)); - ChatCompletionsFunctionToolCall toolcall = ((ChatCompletionsFunctionToolCall) message - .getToolCalls() - .get(0)); - return toolcall - .getFunction() - .getArguments() - .equals("{\"id\": \"ca2fc6bc-1307-4da6-a009-d7bf88dec37b\"}"); - }), - Mockito.any()); - } - - private static OpenAIChatCompletion mockClient(OpenAIAsyncClient client) { - Mockito.when(client.getChatCompletionsWithResponse(Mockito.any(), - Mockito.any(), Mockito.any())) - .thenReturn(Mono.just( - new Response() { - @Override - public int getStatusCode() { - return 200; - } - - @Override - public HttpHeaders getHeaders() { - return new HttpHeaders(); - } - - @Override - public HttpRequest getRequest() { - return null; - } - - @Override - public ChatCompletions getValue() { - try { - String message = EmbeddedResourceLoader.readFile("chatCompletion.txt", - OpenAiChatCompletionTest.class); - - return ChatCompletions.fromJson( - DefaultJsonReader.fromString( - String.format(message, "Snuggles"), new JsonOptions())); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - })); - return new OpenAIChatCompletion( - client, - "test", - "test", - "test"); - } - -} diff --git a/aiservices/openai/src/test/resources/com/microsoft/semantickernel/aiservices/openai/chatcompletion/chatCompletion.txt b/aiservices/openai/src/test/resources/com/microsoft/semantickernel/aiservices/openai/chatcompletion/chatCompletion.txt deleted file mode 100644 index 799c8ab48..000000000 --- a/aiservices/openai/src/test/resources/com/microsoft/semantickernel/aiservices/openai/chatcompletion/chatCompletion.txt +++ /dev/null @@ -1,60 +0,0 @@ -{ - "choices" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "finish_reason" : "stop", - "index" : 0, - "message" : { - "content" : "%s", - "role" : "assistant" - } - } - ], - "created" : 1707253039, - "id" : "chatcmpl-xxx", - "prompt_filter_results" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "prompt_index" : 0 - } - ], - "usage" : { - "completion_tokens" : 131, - "prompt_tokens" : 26, - "total_tokens" : 157 - } -} diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml deleted file mode 100644 index 862cc5184..000000000 --- a/api-test/integration-tests/pom.xml +++ /dev/null @@ -1,246 +0,0 @@ - - - - 4.0.0 - - - com.microsoft.semantic-kernel - api-test - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - Semantic Kernel Integration Tests - integration-tests - jar - - - - com.microsoft.semantic-kernel - semantickernel-syntax-examples - ${project.version} - test - - - org.apache.logging.log4j - log4j-api - test - - - org.apache.logging.log4j - log4j-core - test - - - org.apache.logging.log4j - log4j-slf4j2-impl - test - - - org.mockito - mockito-core - test - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-api - test - - - com.microsoft.semantic-kernel - semantickernel-api - test - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - test - - - com.microsoft.semantic-kernel - semantickernel-data-mysql - test - - - com.microsoft.semantic-kernel - semantickernel-data-hsqldb - test - - - com.microsoft.semantic-kernel - semantickernel-data-sqlite - test - - - com.microsoft.semantic-kernel - semantickernel-data-redis - test - - - - org.xerial - sqlite-jdbc - 3.46.0.0 - - - com.mysql - mysql-connector-j - 9.0.0 - test - - - org.postgresql - postgresql - 42.7.3 - - - org.xerial - sqlite-jdbc - 3.46.1.0 - - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - postgresql - test - - - org.testcontainers - mysql - test - - - com.redis - testcontainers-redis - 2.2.2 - test - - - org.wiremock - wiremock - test - - - - - com.github.victools - jsonschema-generator - test - - - com.github.victools - jsonschema-module-jackson - test - - - - - org.hsqldb - hsqldb - 2.7.3 - test - - - - - - - org.testcontainers - testcontainers-bom - 1.18.3 - pom - import - - - - - - - - org.codehaus.mojo - exec-maven-plugin - 3.1.0 - - - - exec - - recordmappings - - java - - -Djavax.net.ssl.trustStore=scripts/client.truststore - -Djavax.net.ssl.trustStorePassword=password - - com.microsoft.semantickernel.syntaxexamples.WiremockRecord - test - - - - - - - - - - run-wiremocks - - false - - - - - org.codehaus.mojo - exec-maven-plugin - 3.1.0 - - - validate - - exec - - - ./generateCert.sh - scripts - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - - **/WiremockExamplesIT.java - - false - 1 - - -Djavax.net.ssl.trustStore=scripts/client.truststore - -Djavax.net.ssl.trustStorePassword=password - - - foo - https://localhost:8443/ - ../../ - - - - - - - - - - diff --git a/api-test/integration-tests/scripts/generateCert.sh b/api-test/integration-tests/scripts/generateCert.sh deleted file mode 100755 index 300f90d1f..000000000 --- a/api-test/integration-tests/scripts/generateCert.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -KEYTOOL_ARGS="-noprompt -srcstorepass password -deststorepass password -srckeypass password" - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -cd $SCRIPT_DIR - -if [ -f client.keystore ]; then - exit -fi - -rm client.keystore client.truststore server.keystore server.truststore || true - -openssl genrsa -out diagserverCA.key 2048 -openssl req -x509 -new -nodes -key diagserverCA.key -sha256 -days 1024 -out diagserverCA.pem -subj "/C=US/ST=NA/L=NA/O=NA/OU=NA/CN=localhost" -openssl pkcs12 -export -name server-cert -password pass:password -in diagserverCA.pem -inkey diagserverCA.key -out serverkeystore.p12 - -openssl genrsa -out diagclientCA.key 2048 -openssl req -x509 -new -nodes -key diagclientCA.key -sha256 -days 1024 -out diagclientCA.pem -subj "/C=US/ST=NA/L=NA/O=NA/OU=NA/CN=localhost" -openssl pkcs12 -export -name client-cert -password pass:password -in diagclientCA.pem -inkey diagclientCA.key -out clientkeystore.p12 - - -keytool -importkeystore $KEYTOOL_ARGS -destkeystore server.keystore -srckeystore serverkeystore.p12 -srcstoretype pkcs12 -alias server-cert -keytool -import $KEYTOOL_ARGS -alias client-cert -file diagclientCA.pem -keystore server.truststore -keytool -import $KEYTOOL_ARGS -alias server-cert -file diagserverCA.pem -keystore server.truststore - - -keytool -importkeystore $KEYTOOL_ARGS -destkeystore client.keystore -srckeystore clientkeystore.p12 -srcstoretype pkcs12 -alias client-cert -keytool -import $KEYTOOL_ARGS -alias server-cert -file diagserverCA.pem -keystore client.truststore -keytool -import $KEYTOOL_ARGS -alias client-cert -file diagclientCA.pem -keystore client.truststore - -keytool -importkeystore -srckeystore /usr/lib/jvm/default-java/lib/security/cacerts -destkeystore client.truststore -srcstorepass changeit -deststorepass password -keytool -importkeystore -srckeystore /usr/lib/jvm/default-java/lib/security/cacerts -destkeystore server.truststore -srcstorepass changeit -deststorepass password - -rm diagclientCA.key diagserverCA.pem clientkeystore.p12 diagclientCA.pem serverkeystore.p12 diagserverCA.key || true diff --git a/api-test/integration-tests/scripts/recordMappings.sh b/api-test/integration-tests/scripts/recordMappings.sh deleted file mode 100755 index 4616e6931..000000000 --- a/api-test/integration-tests/scripts/recordMappings.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# Run this from the api-test/integration-tests directory - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -ROOT_DIR="$SCRIPT_DIR/.." - -cd $SCRIPT_DIR - -if [ ! -f client.truststore ]; then - ./generateCert.sh -fi - -rm -r "$ROOT_DIR/target/wiremock/mappings" || true -rm -r "$ROOT_DIR/src/test/resources/wiremock/mappings/" || true -mkdir -p "$ROOT_DIR/target/wiremock/mappings" -mkdir -p "$ROOT_DIR/src/test/resources/wiremock/mappings/" - -cd $ROOT_DIR -source "$ROOT_DIR/../../.env.record" -export AZURE_CLIENT_KEY -export CLIENT_ENDPOINT -export PLUGIN_DIR="$ROOT_DIR/../../../" - -../../mvnw clean package -DskipTests -Pcompile-jdk17 - -MAVEN_OPTS="-Djavax.net.ssl.trustStore=scripts/client.truststore -Djavax.net.ssl.trustStorePassword=password" \ -../../mvnw exec:java@recordmappings -Pcompile-jdk17 - -for f in $ROOT_DIR/target/wiremock/mappings/*.json; do - cat $f | jq 'del(.response.headers[])' > /tmp/mapping.json - cat /tmp/mapping.json | json_pp > $f - mv $f src/test/resources/wiremock/mappings/ -done diff --git a/api-test/integration-tests/scripts/runWiremocks.sh b/api-test/integration-tests/scripts/runWiremocks.sh deleted file mode 100755 index 577edf89e..000000000 --- a/api-test/integration-tests/scripts/runWiremocks.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -ROOT_DIR="$SCRIPT_DIR/.." - -cd $SCRIPT_DIR - -if [ ! -f client.truststore ]; then - ./generateCert.sh -fi - - -cd $ROOT_DIR - -../../mvnw clean test -Dtest=WiremockExamplesIT -Prun-wiremocks \ No newline at end of file diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example01NativeFunctionsTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example01NativeFunctionsTest.java deleted file mode 100644 index 74448cde9..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example01NativeFunctionsTest.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -import java.util.Locale; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class Example01NativeFunctionsTest { - - private static class TextPlugin { - - @DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase") - public String uppercase( - @KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) { - return text.toUpperCase(Locale.ROOT); - } - - } - - @Test - public void run() { - // Load native plugin - TextPlugin text = new TextPlugin(); - - // Use function without kernel - String result = text.uppercase("ciao!"); - - Assertions.assertEquals("CIAO!", result); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example03_ArgumentsTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example03_ArgumentsTest.java deleted file mode 100644 index dd283952d..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example03_ArgumentsTest.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments.StaticTextPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * Demonstrates running a pipeline (a sequence of functions) on a - * {@code com.microsoft.semantickernel.orchestration.SKContext} - */ -public class Example03_ArgumentsTest { - - @Test - public void main() { - Kernel kernel = Kernel.builder().build(); - - // Load native plugin - KernelPlugin functionCollection = KernelPluginFactory - .createFromObject(new StaticTextPlugin(), "text"); - - KernelArguments arguments = KernelArguments.builder() - .withInput("Today is: ") - .withVariable("day", "Monday") - .build(); - - FunctionResult resultValue = kernel.invokeAsync( - functionCollection.get("AppendDay")) - .withArguments(arguments) - .block(); - - Assertions.assertEquals("Today is: Monday", resultValue.getResult()); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example05_InlineFunctionDefinitionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example05_InlineFunctionDefinitionTest.java deleted file mode 100644 index d791ec9c2..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/Example05_InlineFunctionDefinitionTest.java +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; - -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -@WireMockTest -public class Example05_InlineFunctionDefinitionTest { - - @Test - public void main(WireMockRuntimeInfo wmRuntimeInfo) { - final OpenAIAsyncClient client = new OpenAIClientBuilder() - .endpoint("http://localhost:" + wmRuntimeInfo.getHttpPort()) - .buildAsyncClient(); - - OpenAIChatCompletion chatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(OpenAIChatCompletion.class, chatCompletion) - .build(); - - System.out.println("======== Inline Function Definition ========"); - - // Function defined using few-shot design pattern - String promptTemplate = """ - Generate a creative reason or excuse for the given event. - Be creative and be funny. Let your imagination run wild. - - Event: I am running late. - Excuse: I was being held ransom by giraffe gangsters. - - Event: I haven't been to the gym for a year - Excuse: I've been too busy training my pet dragon. - - Event: {{$input}} - """.stripIndent(); - - var excuseFunction = new KernelFunctionFromPrompt.Builder() - .withName("Excuse") - .withTemplate(promptTemplate) - .withDefaultExecutionSettings( - new PromptExecutionSettings.Builder() - .withTemperature(0.4) - .withTopP(1) - .withMaxTokens(100) - .build()) - .build(); - - WireMockUtil.mockChatCompletionResponse("I missed the F1 final race", "a-response"); - - var result = kernel.invokeAsync(excuseFunction) - .withArguments( - KernelArguments.builder() - .withInput("I missed the F1 final race") - .build()) - .block(); - - Assertions.assertEquals("a-response", result.getResult()); - - WireMockUtil.mockChatCompletionResponse("sorry I forgot your birthday", "a-response-2"); - - result = kernel.invokeAsync(excuseFunction) - .withArguments( - KernelArguments.builder() - .withInput("sorry I forgot your birthday") - .build()) - .block(); - - Assertions.assertEquals("a-response-2", result.getResult()); - - WireMockUtil.mockChatCompletionResponse("Translate this date ", "a-response-3"); - - var date = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC) - .format(Instant.ofEpochSecond(1)); - var message = "Translate this date " + date + " to French format"; - var fixedFunction = KernelFunction.createFromPrompt(message) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(100) - .build()) - .build(); - - FunctionResult fixedFunctionResult = kernel - .invokeAsync(fixedFunction) - .block(); - - Assertions.assertEquals("a-response-3", fixedFunctionResult.getResult()); - - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java deleted file mode 100644 index a555937ed..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import org.junit.Ignore; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class ImportingMultiplePluginsTest { - @Disabled - @Test - public void canImportMultiplePlugins() { - KernelPlugin summarize = KernelPluginFactory.importPluginFromResourcesDirectory( - "Plugins", - "SummarizePlugin", - "Summarize", - null, - String.class); - - KernelPlugin topics = KernelPluginFactory.importPluginFromResourcesDirectory( - "Plugins", - "SummarizePlugin", - "Topics", - null, - String.class); - - KernelPlugin notegen = KernelPluginFactory.importPluginFromResourcesDirectory( - "Plugins", - "SummarizePlugin", - "Notegen", - null, - String.class); - - Kernel kernel = Kernel.builder() - .withPlugin(summarize) - .withPlugin(topics) - .withPlugin(notegen) - .build(); - - Assertions.assertEquals(3, - kernel.getPlugin("SummarizePlugin").getFunctions().size()); - Assertions.assertEquals("Summarize", - kernel.getPlugin("SummarizePlugin").get("Summarize").getName()); - Assertions.assertEquals("Topics", - kernel.getPlugin("SummarizePlugin").get("Topics").getName()); - Assertions.assertEquals("Notegen", - kernel.getPlugin("SummarizePlugin").get("Notegen").getName()); - - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/KernelHooksTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/KernelHooksTest.java deleted file mode 100644 index 4a128fb16..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/KernelHooksTest.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.Kernel.Builder; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook; -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.OutputVariable; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -@WireMockTest -public class KernelHooksTest { - - private static Builder getKernelBuilder(WireMockRuntimeInfo wmRuntimeInfo) { - final OpenAIAsyncClient client = new OpenAIClientBuilder() - .endpoint("http://localhost:" + wmRuntimeInfo.getHttpPort()) - .buildAsyncClient(); - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId("gpt-35-turbo") - .withOpenAIAsyncClient(client) - .build(); - - return Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion); - } - - @Test - public void getUsageAsync(WireMockRuntimeInfo wmRuntimeInfo) { - WireMockUtil.mockChatCompletionResponse("Write a random paragraph about", "a-response"); - Kernel kernel = getKernelBuilder(wmRuntimeInfo).build(); - - System.out.println("\n======== Get Usage Data ========\n"); - - // Initialize prompt - String functionPrompt = "Write a random paragraph about: {{$input}}."; - - KernelFunction excuseFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Excuse") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(100) - .withTemperature(0.4) - .withTopP(1) - .build()) - .withOutputVariable(new OutputVariable<>("result", String.class)) - .build(); - - AtomicBoolean preHookTriggered = new AtomicBoolean(false); - - FunctionInvokingHook preHook = event -> { - preHookTriggered.set(true); - return event; - }; - - AtomicBoolean removedPreExecutionHandlerTriggered = new AtomicBoolean(false); - - FunctionInvokingHook removedPreExecutionHandler = event -> { - removedPreExecutionHandlerTriggered.set(true); - return event; - }; - - AtomicBoolean postExecutionHandlerTriggered = new AtomicBoolean(false); - - FunctionInvokedHook postExecutionHandler = event -> { - postExecutionHandlerTriggered.set(true); - return event; - }; - - kernel.getGlobalKernelHooks().addHook(preHook); - - // Demonstrate pattern for removing a handler. - kernel.getGlobalKernelHooks().addHook("pre-invoke-removed", removedPreExecutionHandler); - kernel.getGlobalKernelHooks().removeHook("pre-invoke-removed"); - kernel.getGlobalKernelHooks().addHook(postExecutionHandler); - - kernel.invokeAsync( - excuseFunction) - .withArguments( - KernelArguments - .builder() - .withVariable("input", "I missed the F1 final race") - .build()) - .block(); - - Assertions.assertTrue(preHookTriggered.get()); - Assertions.assertFalse(removedPreExecutionHandlerTriggered.get()); - Assertions.assertTrue(postExecutionHandlerTriggered.get()); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/RenderingTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/RenderingTest.java deleted file mode 100644 index ff4655d26..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/RenderingTest.java +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.List; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -@WireMockTest -public class RenderingTest { - - private WireMockServer wm; - - @BeforeEach - public void before() { - wm = new WireMockServer(); - } - - @AfterEach - public void after() { - wm.stop(); - } - - @Test - public void textSemanticKernelTemplateXml() { - buildTextKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{$value}} - """) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "\"hello world\"") - .build()) - .block(); - - // The actual body will be escaped as its json - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString() - .contains("\\\"hello world\\\"")); - } - - @Test - public void textSemanticKernelTemplate() { - buildTextKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{$value}} - """) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "{{$ignore}}") - .withVariable("ignore", "dont show") - .build()) - .block(); - - Assertions.assertFalse( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show")); - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}")); - } - - @Test - public void textHandleBarsTemplate() { - buildTextKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{value}} - """) - .withTemplateFormat("handlebars") - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "{{ignore}}") - .withVariable("ignore", "dont show") - .build()) - .block(); - - Assertions.assertFalse( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show")); - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{ignore}}")); - } - - @Test - public void chatSemanticKernelTemplateXml() { - buildChatKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{$value}} - """) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "\"hello world\"") - .build()) - .block(); - - // The actual body will be escaped as its json - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString() - .contains("\\\"hello world\\\"")); - } - - @Test - public void chatSemanticKernelTemplate() { - buildChatKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{$value}} - """) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "{{$ignore}}") - .withVariable("ignore", "dont show") - .build()) - .block(); - - Assertions.assertFalse( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show")); - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}")); - } - - @Test - public void chatHandleBarsTemplate() { - buildChatKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{value}} - """) - .withTemplateFormat("handlebars") - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "{{ignore}}") - .withVariable("ignore", "dont show") - .build()) - .block(); - - Assertions.assertFalse( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show")); - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{ignore}}")); - } - - @Test - public void chatSemanticKernelTemplate2() { - buildChatKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - Value: {{$value}} - """) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build()) - .withArguments(KernelArguments - .builder() - .withVariable("value", "{{$ignore}}") - .withVariable("ignore", "dont show") - .build()) - .block(); - - Assertions.assertFalse( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show")); - Assertions.assertTrue( - wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}")); - } - - @DefineKernelFunction(name = "WithEmptyListReturn") - public List WithEmptyListReturn() { - return List.of(); - } - - @DefineKernelFunction(name = "WithListReturn") - public List WithListReturn() { - return List.of(1, 2, 3); - } - - @DefineKernelFunction(name = "WithListReturn2", returnType = "java.util.List") - public List WithListReturn2() { - return List.of(4, 5, 6); - } - - @DefineKernelFunction(name = "WithListReturn3", returnType = "java.util.List") - public Mono> WithListReturn3() { - return Mono.just(List.of(7, 8, 9)); - } - - @DefineKernelFunction(name = "WithListReturn4", returnType = "java.util.List") - public Mono> WithListReturn4() { - return Mono.just(List.of()); - } - - @Test - public void canHandleIterableReturnFromFunction() { - buildChatKernel() - .invokeAsync( - KernelFunction - .createFromPrompt(""" - {{RenderingTest-WithEmptyListReturn}} - {{RenderingTest-WithListReturn}} - {{RenderingTest-WithListReturn2}} - {{RenderingTest-WithListReturn3}} - {{RenderingTest-WithListReturn4}} - """) - .withTemplateFormat("handlebars") - .build()) - .block(); - - String requestBody = wm.getAllServeEvents().get(0).getRequest().getBodyAsString(); - Assertions.assertTrue(requestBody.contains("\"content\":\"[]")); - Assertions.assertTrue(requestBody.contains("\"content\":\"[1, 2, 3]")); - Assertions.assertTrue(requestBody.contains("\"content\":\"[4, 5, 6]")); - Assertions.assertTrue(requestBody.contains("\"content\":\"[7, 8, 9]")); - } - - private Kernel buildTextKernel() { - wm.addStubMapping( - stubFor( - ToolCallBehaviourTest.buildTextResponse(" ", """ - "choices": [ - { - "text": "Value: bar" - } - ] - """))); - wm.start(); - - final OpenAIAsyncClient client = new OpenAIClientBuilder() - .endpoint("http://localhost:" + wm.port() + "/") - .buildAsyncClient(); - - TextGenerationService textGenerationService = OpenAITextGenerationService.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(TextGenerationService.class, textGenerationService) - .build(); - return kernel; - } - - private Kernel buildChatKernel() { - wm.addStubMapping( - stubFor( - ToolCallBehaviourTest.buildResponse(" ", """ - "choices" : [ - { - "finish_reason" : "stop", - "index" : 0, - "message" : { - "content" : "done", - "role" : "assistant" - } - } - ] - """))); - wm.start(); - - final OpenAIAsyncClient client = new OpenAIClientBuilder() - .endpoint("http://localhost:" + wm.port() + "/") - .buildAsyncClient(); - - ChatCompletionService textGenerationService = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, textGenerationService) - .withPlugin(KernelPluginFactory.createFromObject(this, "RenderingTest")) - .build(); - return kernel; - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java deleted file mode 100644 index 4ec677742..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java +++ /dev/null @@ -1,311 +0,0 @@ -package com.microsoft.semantickernel.tests; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.models.ChatCompletions; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.core.http.HttpHeaders; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.rest.RequestOptions; -import com.azure.core.http.rest.Response; -import com.azure.json.JsonOptions; -import com.azure.json.JsonWriter; -import com.azure.json.implementation.DefaultJsonReader; -import com.azure.json.implementation.DefaultJsonWriter; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.converters.ContextVariableJacksonConverter; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader.ResourceLocation; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionYaml; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.io.IOException; -import java.io.StringWriter; -import org.apache.commons.text.StringEscapeUtils; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import reactor.core.publisher.Mono; - -public class ResponseSchemaTest { - - public static class TestClass { - - private final String name; - - @JsonCreator - public TestClass( - @JsonProperty("name") String name) { - this.name = name; - } - - public String getName() { - return name; - } - } - - @Test - public void sendsResponseSchemaFromTemplate() throws IOException { - OpenAIAsyncClient client = getOpenAIAsyncClient( - """ - { - "name": "Test name" - } - """ - .stripIndent()); - Kernel kernel = buildKernel(client); - - var getIntent = KernelFunctionYaml.fromPromptYaml( - EmbeddedResourceLoader - .readFile("responseSchema.prompt.yaml", ResponseSchemaTest.class, - ResourceLocation.CLASSPATH_ROOT), - new HandlebarsPromptTemplateFactory()); - - FunctionResult response = getIntent.invokeAsync(kernel) - .withResultTypeAutoConversion(TestClass.class) - .block(); - - verifyCalled(client, - """ - { - "type":"json_schema", - "json_schema":{ - "strict":true, - "name":"Test", - "schema":{ - "type" : "object", - "properties" : { - "name" : { - "type" : "string" - } - }, - "required" : [ - "name" - ], - "additionalProperties" : false - } - } - } - """ - ); - } - - @Disabled - @Test - public void sendsResponseSchema() { - OpenAIAsyncClient client = getOpenAIAsyncClient( - """ - { - "name": "Test name" - } - """ - .stripIndent()); - - Kernel kernel = buildKernel(client); - - PromptExecutionSettings promptExecutionSettings = PromptExecutionSettings.builder() - .withResponseFormat( - JsonSchemaResponseFormat.builder() - .setResponseFormat(TestClass.class) - .setName("Test") - .build() - ) - .build(); - - FunctionResult response = kernel.invokePromptAsync( - "Generate TestClass") - .withTypeConverter(ContextVariableJacksonConverter.create(TestClass.class)) - .withResultType(TestClass.class) - .withPromptExecutionSettings(promptExecutionSettings) - .block(); - - verifyCalled(client, - """ - { - "type":"json_schema", - "json_schema":{ - "strict":true, - "name":"Test", - "schema":{ - "type" : "object", - "properties" : { - "name" : { - "type" : "string" - } - }, - "required" : [ "name" ], - "additionalProperties" : false - } - } - } - """ - ); - } - - private static void verifyCalled(OpenAIAsyncClient client, String expected) { - Mockito.verify(client, Mockito.atLeastOnce()) - .getChatCompletionsWithResponse( - Mockito.any(), - Mockito.argThat( - (ChatCompletionsOptions chatCompletionsOptions) -> { - StringWriter writer = new StringWriter(); - try { - JsonWriter jsonWriter = DefaultJsonWriter.toWriter( - writer, - new JsonOptions() - ); - JsonWriter format = chatCompletionsOptions.getResponseFormat() - .toJson(jsonWriter); - jsonWriter.flush(); - writer.flush(); - - String json = String.valueOf(writer.getBuffer()) - .replaceAll("\n", "") - .replaceAll("\r", "") - .replaceAll(" +", ""); - String expectedClean = expected - .stripIndent() - .replaceAll("\n", "") - .replaceAll("\r", "") - .replaceAll(" +", ""); - - return json.equals(expectedClean); - - } catch (IOException e) { - throw new RuntimeException(e); - } - }), - Mockito.any()); - } - - private @NotNull OpenAIAsyncClient getOpenAIAsyncClient(String response) { - OpenAIAsyncClient client = Mockito.mock(OpenAIAsyncClient.class); - - Mockito.when( - client.getChatCompletionsWithResponse( - Mockito.any(), - Mockito.any(), - Mockito.any())) - .thenReturn( - Mono.just( - new Response() { - @Override - public int getStatusCode() { - return 200; - } - - @Override - public HttpHeaders getHeaders() { - return new HttpHeaders(); - } - - @Override - public HttpRequest getRequest() { - return null; - } - - @Override - public ChatCompletions getValue() { - return buildResponse(response); - } - })); - return client; - } - - - private ChatCompletions buildResponse(String response) { - String str = String.format(""" - { - "choices" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "finish_reason" : "stop", - "index" : 0, - "message" : { - "content" : "%s", - "role" : "assistant" - } - } - ], - "created" : 1707253039, - "id" : "chatcmpl-xxx", - "prompt_filter_results" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "prompt_index" : 0 - } - ], - "usage" : { - "completion_tokens" : 131, - "prompt_tokens" : 26, - "total_tokens" : 157 - } - } - """, StringEscapeUtils.escapeJson(response)); - - try { - return ChatCompletions.fromJson( - DefaultJsonReader.fromString( - str, new JsonOptions()) - ); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - private Kernel buildKernel(OpenAIAsyncClient client) { - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("a-model") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - return kernel; - - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ToolCallBehaviourTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ToolCallBehaviourTest.java deleted file mode 100644 index 5f80a6e00..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ToolCallBehaviourTest.java +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import com.github.tomakehurst.wiremock.matching.ContainsPattern; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -@WireMockTest -public class ToolCallBehaviourTest { - - private WireMockServer wm; - - @BeforeEach - public void before() { - wm = new WireMockServer(); - } - - @AfterEach - public void after() { - wm.stop(); - } - - @Test - public void nonAutoInvokedIsNotCalled() throws NoSuchMethodException { - ChatCompletionService chatCompletionService = getChatCompletionService(); - - TestPlugin testPlugin = Mockito.spy(new TestPlugin()); - KernelFunction method = KernelFunctionFromMethod.builder() - .withFunctionName("doIt") - .withMethod(TestPlugin.class.getMethod("doIt")) - .withTarget(testPlugin) - .withPluginName("apluginname") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin( - new KernelPlugin( - "apluginname", - "A plugin description", - Map.of("doIt", method))) - .build(); - - ChatHistory messages = new ChatHistory(); - messages.addMessage( - ChatMessageTextContent.userMessage("Call A function")); - - List> result = chatCompletionService - .getChatMessageContentsAsync( - messages, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(false, method)) - .build()) - .block(); - - List toolCalls = ((OpenAIChatMessageContent) CollectionUtil.getLastOrNull( - result)) - .getToolCall(); - - Assertions.assertNotNull(toolCalls); - Assertions.assertEquals(1, toolCalls.size()); - Assertions.assertEquals("apluginname", - CollectionUtil.getLastOrNull(toolCalls).getPluginName()); - Assertions.assertEquals("doIt", CollectionUtil.getLastOrNull(toolCalls).getFunctionName()); - Assertions.assertEquals("call_abc123", CollectionUtil.getLastOrNull(toolCalls).getId()); - - Mockito.verify(testPlugin, Mockito.times(0)).doIt(); - } - - @Test - public void toolIsInvoked() throws NoSuchMethodException { - ChatCompletionService chatCompletionService = getChatCompletionService(); - - TestPlugin testPlugin = Mockito.spy(new TestPlugin()); - KernelFunction method = KernelFunctionFromMethod.builder() - .withFunctionName("doIt") - .withMethod(TestPlugin.class.getMethod("doIt")) - .withTarget(testPlugin) - .withPluginName("apluginname") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin( - new KernelPlugin( - "apluginname", - "A plugin description", - Map.of("doIt", method))) - .build(); - - ChatHistory messages = new ChatHistory(); - messages.addMessage( - ChatMessageTextContent.userMessage("Call A function")); - - List> result = chatCompletionService - .getChatMessageContentsAsync( - messages, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .build()) - .block(); - - Assertions.assertTrue( - CollectionUtil.getLastOrNull(result).getContent().contains("tool call done")); - Mockito.verify(testPlugin, Mockito.times(1)).doIt(); - - result = chatCompletionService - .getChatMessageContentsAsync( - messages, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(true, Arrays.asList(method))) - .build()) - .block(); - - Assertions.assertTrue( - CollectionUtil.getLastOrNull(result).getContent().contains("tool call done")); - Mockito.verify(testPlugin, Mockito.times(2)).doIt(); - - result = chatCompletionService - .getChatMessageContentsAsync( - messages, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(true, method)) - .build()) - .block(); - - Assertions.assertTrue( - CollectionUtil.getLastOrNull(result).getContent().contains("tool call done")); - Mockito.verify(testPlugin, Mockito.times(3)).doIt(); - } - - - @Test - public void toolCallingHistoryPassed() throws NoSuchMethodException { - ChatCompletionService chatCompletionService = getChatCompletionService(); - - TestPlugin testPlugin = Mockito.spy(new TestPlugin()); - KernelFunction method = KernelFunctionFromMethod.builder() - .withFunctionName("doIt") - .withMethod(TestPlugin.class.getMethod("doIt")) - .withTarget(testPlugin) - .withPluginName("apluginname") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin( - new KernelPlugin( - "apluginname", - "A plugin description", - Map.of("doIt", method))) - .build(); - - ChatHistory messages = new ChatHistory(); - messages.addMessage( - new ChatMessageContent<>( - AuthorRole.USER, - "Call A function")); - - List> result = chatCompletionService - .getChatMessageContentsAsync( - messages, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .build()) - .block(); - - ChatHistory newHistory = new ChatHistory(result); - newHistory.addMessage(AuthorRole.USER, "do something else"); - - List> result2 = chatCompletionService - .getChatMessageContentsAsync( - newHistory, - kernel, - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .build()) - .block(); - Assertions.assertTrue(result2.size() == 6); - } - - private ChatCompletionService getChatCompletionService() { - wm - .addStubMapping( - stubFor( - buildResponse("Call A function", """ - "choices": [ - { - "index": 0, - "message": { - "role": "assistant", - "content": null, - "tool_calls": [ - { - "id": "call_abc123", - "type": "function", - "function": { - "name": "apluginname-doIt", - "arguments": "{}" - } - } - ] - }, - "logprobs": null, - "finish_reason": "tool_calls" - } - ] - """))); - - wm.addStubMapping( - stubFor( - buildResponse("Tool call performed", """ - "choices" : [ - { - "finish_reason" : "stop", - "index" : 0, - "message" : { - "content" : "tool call done", - "role" : "assistant" - } - } - ] - """))); - - wm.start(); - - final OpenAIAsyncClient client = new OpenAIClientBuilder() - .endpoint("http://localhost:" + wm.port() + "/") - .buildAsyncClient(); - - return OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build(); - } - - - public static MappingBuilder buildTextResponse(String bodyMatcher, String responseBody) { - return post(urlEqualTo( - "//openai/deployments/gpt-35-turbo-2/completions?api-version=2025-01-01-preview")) - .withRequestBody(new ContainsPattern(bodyMatcher)) - .willReturn( - aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(formTextResponse(responseBody))); - } - - public static MappingBuilder buildResponse(String bodyMatcher, String responseBody) { - return post(urlEqualTo( - "//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2025-01-01-preview")) - .withRequestBody(new ContainsPattern(bodyMatcher)) - .willReturn( - aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(formResponse(responseBody))); - } - - public static class TestPlugin { - - public String doIt() { - return "Tool call performed"; - } - } - - private static String formTextResponse(String chatChoices) { - return """ - { - "id": "cmpl-3QJ9z1J9z1J9z1J9z1J9z1J9", - "usage": { - "total_tokens": 4, - "completion_tokens": 1, - "prompt_tokens": 1 - }, - %s - } - """.formatted(chatChoices); - } - - private static String formResponse(String chatChoices) { - return """ - { - %s, - "created" : 1707253061, - "id" : "chatcmpl-xxx", - "model" : "gpt-35-turbo", - "object" : "chat.completion", - "prompt_filter_results" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "prompt_index" : 0 - } - ], - "usage" : { - "completion_tokens" : 67, - "prompt_tokens" : 17, - "total_tokens" : 84 - } - } - """.formatted(chatChoices); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WireMockUtil.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WireMockUtil.java deleted file mode 100644 index 93adcd818..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WireMockUtil.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; - -public class WireMockUtil { - - public static void mockCompletionResponse( - String regexMatcher, - String response) { - String body = """ - { - "id": "1", - "object": "text_completion", - "created": 1589478378, - "model": "text-davinci-003", - "system_fingerprint": "fp_44709d6fb", - "choices": [ - { - "text": "%s", - "index": 0, - "logprobs": null, - "finish_reason": "length" - } - ], - "usage": { - "prompt_tokens": 1, - "completion_tokens": 2, - "total_tokens": 3 - } - } - """ - .formatted(response); - - WireMock.reset(); - WireMock.stubFor(WireMock - .post(new UrlPathPattern( - new RegexPattern("/openai/deployments/text-davinci-003/completions"), true)) - .withRequestBody(WireMock.matching(".*" + regexMatcher + ".*")) - .willReturn(WireMock.ok() - .withBody(body))); - } - - public static void mockChatCompletionResponse( - String regexMatcher, - String response) { - String body = """ - { - "choices" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "finish_reason" : "length", - "index" : 0, - "message" : { - "content" : "%s", - "role" : "assistant" - } - } - ], - "created" : 1707253019, - "id" : "chatcmpl-xxx", - "model" : "gpt-35-turbo", - "object" : "chat.completion", - "prompt_filter_results" : [ - { - "content_filter_results" : { - "hate" : { - "filtered" : false, - "severity" : "safe" - }, - "self_harm" : { - "filtered" : false, - "severity" : "safe" - }, - "sexual" : { - "filtered" : false, - "severity" : "safe" - }, - "violence" : { - "filtered" : false, - "severity" : "safe" - } - }, - "prompt_index" : 0 - } - ], - "usage" : { - "completion_tokens" : 256, - "prompt_tokens" : 69, - "total_tokens" : 325 - } - } - - """ - .formatted(response); - - WireMock.reset(); - WireMock.stubFor(WireMock - .post(new UrlPathPattern( - new RegexPattern("/openai/deployments/gpt-35-turbo/chat/completions"), true)) - .withRequestBody(WireMock.matching(".*" + regexMatcher + ".*")) - .willReturn(WireMock.ok() - .withBody(body))); - } - -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockExamplesIT.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockExamplesIT.java deleted file mode 100644 index f01b40d16..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockExamplesIT.java +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.microsoft.semantickernel.samples.syntaxexamples.Example43_GetModelResult; -import com.microsoft.semantickernel.samples.syntaxexamples.Example49_LogitBias; -import com.microsoft.semantickernel.samples.syntaxexamples.Example55_TextChunker; -import com.microsoft.semantickernel.samples.syntaxexamples.Example57_KernelHooks; -import com.microsoft.semantickernel.samples.syntaxexamples.Example61_MultipleLLMs; -import com.microsoft.semantickernel.samples.syntaxexamples.Example62_CustomAIServiceSelector; -import com.microsoft.semantickernel.samples.syntaxexamples.Example69_MutableKernelPlugin; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example17_ChatGPT; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example33_Chat; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example44_MultiChatCompletion; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example63_ChatCompletionPrompts; -import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example41_HttpClientUsage; -import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example58_ConfigureExecutionSettings; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example01_NativeFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example05_InlineFunctionDefinition; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example09_FunctionTypes; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example27_PromptFunctionsUsingChatGPT; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.java.FunctionsWithinPrompts_Example; -import com.microsoft.semantickernel.samples.syntaxexamples.java.KernelFunctionYaml_Example; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.util.ArrayDeque; -import java.util.Arrays; -import java.util.List; -import java.util.Queue; -import java.util.stream.Stream; -import com.microsoft.semantickernel.samples.syntaxexamples.plugin.Example10_DescribeAllPluginsAndFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.plugin.Example13_ConversationSummaryPlugin; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example06_TemplateLanguage; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example56_TemplateMethodFunctionsWithMultipleArguments; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example64_MultiplePromptTemplates; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.TestFactory; -import org.mockito.Mockito; - -public class WiremockExamplesIT { - - public static List> mains = Arrays.asList( - FunctionsWithinPrompts_Example.class, - KernelFunctionYaml_Example.class, - Example01_NativeFunctions.class, - Example03_Arguments.class, - Example05_InlineFunctionDefinition.class, - Example06_TemplateLanguage.class, - //Example08_RetryHandler.class, - Example09_FunctionTypes.class, - Example10_DescribeAllPluginsAndFunctions.class, - //Example11_WebSearchQueries.class, - Example13_ConversationSummaryPlugin.class, - Example17_ChatGPT.class, - //Example26_AADAuth.class, - - Example27_PromptFunctionsUsingChatGPT.class, - - // Difficulty with time causing wiremock to fail - //Example30_ChatWithPrompts.class, - Example33_Chat.class, - Example41_HttpClientUsage.class, - Example43_GetModelResult.class, - Example44_MultiChatCompletion.class, - Example49_LogitBias.class, - Example55_TextChunker.class, - Example56_TemplateMethodFunctionsWithMultipleArguments.class, - Example57_KernelHooks.class, - Example58_ConfigureExecutionSettings.class, - Example60_AdvancedMethodFunctions.class, - Example61_MultipleLLMs.class, - Example62_CustomAIServiceSelector.class, - Example63_ChatCompletionPrompts.class, - Example64_MultiplePromptTemplates.class, - Example69_MutableKernelPlugin.class); - - public static WireMockServer createWiremockServer(String dir) { - return new WireMockServer( - WireMockConfiguration.wireMockConfig() - .httpsPort(8443) - .trustStorePath("scripts/client.truststore") - .trustStorePassword("password") - .trustStoreType("jks") - .keystorePath("scripts/server.keystore") - .keystorePassword("password") - .keystoreType("jks") - .usingFilesUnderDirectory(dir)); - } - - public static void main(String[] args) throws IOException { - mockInputStream(); - - new WiremockExamplesIT() - .runSamplesTest() - .forEach(it -> { - try { - it.getExecutable().execute(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - }); - } - - private static void mockInputStream() throws IOException { - FunctionsWithinPrompts_Example.INPUT = Mockito.mock(InputStream.class); - - Queue messages = new ArrayDeque<>(); - - messages.addAll(Arrays.asList( - "Can you draft me an email to the marketing team?", - "Tell them to go ahead with the plan", - "That is all")); - - Mockito - .when(FunctionsWithinPrompts_Example.INPUT.read( - Mockito.any(byte[].class), - Mockito.anyInt(), - Mockito.anyInt())) - .then(invocation -> { - String message = messages.poll() + "\n"; - byte[] bytes = invocation.getArgument(0); - System.arraycopy(message.getBytes(), 0, bytes, 0, message.getBytes().length); - - return message.getBytes().length; - }); - } - - @TestFactory - public Stream runSamplesTest() { - return mains - .stream() - .map( - testClazz -> DynamicTest - .dynamicTest( - testClazz.getSimpleName() + "Test", - () -> { - mockInputStream(); - System.out.println("Running: " + testClazz.getSimpleName()); - WireMockServer server = null; - try { - Method main = testClazz.getMethod("main", - String[].class); - - server = createWiremockServer("src/test/resources/wiremock"); - - server.start(); - main.invoke(null, new Object[] { null }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - if (server != null) { - server.stop(); - } - } - })); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockRecord.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockRecord.java deleted file mode 100644 index 90a02f11c..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/WiremockRecord.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.tests; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder; -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.UUID; - -public class WiremockRecord { - - public static void main(String[] args) throws IOException { - record( - () -> { - WiremockExamplesIT.mains.forEach(testClazz -> { - try { - Method main = testClazz.getMethod("main", String[].class); - main.invoke(null, new Object[] { null }); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - }, - args[0]); - } - - public static void compressRecordings(Path mappings) throws IOException { - Files.newDirectoryStream(mappings) - .forEach(path -> { - try { - JsonNode data = new ObjectMapper().readTree(path.toFile()); - - JsonNode body = new ObjectMapper().readTree( - data.get("response").get("body").asText()); - - if (body.get("id").asText().contains("chatcmpl-")) { - - ((ObjectNode) body).put("id", "chatcmpl-xxx"); - - body - .get("choices") - .forEach(choice -> { - ((ObjectNode) choice.get("message")).put("content", - UUID.randomUUID().toString()); - }); - - ((ObjectNode) data.get("response")).put("body", body.toString()); - } else if (body.get("id").asText().contains("cmpl-")) { - - ((ObjectNode) body).put("id", "cmpl-xxx"); - - body - .get("choices") - .forEach(choice -> { - ((ObjectNode) choice).put("text", UUID.randomUUID().toString()); - }); - - ((ObjectNode) data.get("response")).put("body", body.toString()); - } - - Files.writeString(path, data.toPrettyString()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - - public static void record(Runnable run, String targetUrl) throws IOException { - Path dir = Path.of("target", "wiremock"); - if (dir.toFile().exists()) { - dir.toFile().delete(); - } - - Files.createDirectories(dir.resolve("mappings")); - - System.out.println("Recording to: " + dir.toFile().getCanonicalPath()); - - WireMockServer wireMockServer = WiremockExamplesIT.createWiremockServer( - dir.toFile().getCanonicalPath() + "/"); - wireMockServer.start(); - wireMockServer.startRecording( - new RecordSpecBuilder() - .forTarget(targetUrl) - .makeStubsPersistent(true) - .build()); - - try { - run.run(); - } finally { - wireMockServer.stopRecording().getStubMappings(); - wireMockServer.stop(); - } - - compressRecordings(dir.resolve("mappings")); - - System.out.println("Saved output to: " + dir.toFile().getAbsolutePath()); - - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/Hotel.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/Hotel.java deleted file mode 100644 index 6b33c380b..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/Hotel.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.microsoft.semantickernel.tests.data.jdbc; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import java.util.List; - -public class Hotel { - @JsonProperty("hotelId") - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final String name; - - @VectorStoreRecordData - private final int code; - - @JsonProperty("summary") - @VectorStoreRecordData() - private final String description; - - @JsonProperty("summaryEmbedding1") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.EUCLIDEAN_DISTANCE) - private final List euclidean; - - @JsonProperty("summaryEmbedding2") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private final List cosineDistance; - - @JsonProperty("summaryEmbedding3") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.DOT_PRODUCT) - private final List dotProduct; - - @JsonProperty("indexedSummaryEmbedding") - @VectorStoreRecordVector(dimensions = 8, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.EUCLIDEAN_DISTANCE) - private final List indexedEuclidean; - - @VectorStoreRecordData(isFilterable = true) - private final List tags; - - @VectorStoreRecordData - private double rating; - - public Hotel() { - this(null, null, 0, null, null, null, null, null, 0.0, null); - } - - @JsonCreator - public Hotel( - @JsonProperty("hotelId") String id, - @JsonProperty("name") String name, - @JsonProperty("code") int code, - @JsonProperty("summary") String description, - @JsonProperty("summaryEmbedding1") List euclidean, - @JsonProperty("summaryEmbedding2") List cosineDistance, - @JsonProperty("summaryEmbedding3") List dotProduct, - @JsonProperty("indexedSummaryEmbedding") List indexedEuclidean, - @JsonProperty("rating") double rating, - @JsonProperty("tags") List tags) { - this.id = id; - this.name = name; - this.code = code; - this.description = description; - this.euclidean = euclidean; - this.cosineDistance = euclidean; - this.dotProduct = euclidean; - this.indexedEuclidean = euclidean; - this.rating = rating; - this.tags = tags; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public int getCode() { - return code; - } - - public String getDescription() { - return description; - } - - public List getEuclidean() { - return euclidean; - } - - public List getIndexedEuclidean() { - return indexedEuclidean; - } - - public double getRating() { - return rating; - } - - public List getTags() { - return tags; - } - - public void setRating(double rating) { - this.rating = rating; - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreRecordCollectionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreRecordCollectionTest.java deleted file mode 100644 index 6bc99f25d..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,551 +0,0 @@ -package com.microsoft.semantickernel.tests.data.jdbc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; - -import com.microsoft.semantickernel.data.jdbc.hsqldb.HSQLDBVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.mysql.MySQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.sqlite.SQLiteVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.mysql.cj.jdbc.MysqlDataSource; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.stream.Stream; -import javax.annotation.Nonnull; -import javax.sql.DataSource; -import org.hsqldb.jdbc.JDBCDataSourceFactory; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.MethodSource; -import org.postgresql.ds.PGSimpleDataSource; -import org.sqlite.SQLiteDataSource; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - - -@Testcontainers -public class JDBCVectorStoreRecordCollectionTest { - - @Container - private static final MySQLContainer MYSQL_CONTAINER = new MySQLContainer<>("mysql:5.7.34"); - - private static final DockerImageName PGVECTOR = DockerImageName.parse("pgvector/pgvector:pg16") - .asCompatibleSubstituteFor("postgres"); - @Container - private static final PostgreSQLContainer POSTGRESQL_CONTAINER = new PostgreSQLContainer<>( - PGVECTOR); - - public enum QueryProvider { - MySQL, - PostgreSQL, - SQLite, - HSQLDB - } - - static Path createTempDbFile(String prefix) { - try { - Path file = Files.createTempFile(prefix, ".db"); - file.toFile().deleteOnExit(); - return file; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private JDBCVectorStoreRecordCollection buildRecordCollection(QueryProvider provider, - @Nonnull String collectionName) { - SQLVectorStoreQueryProvider queryProvider; - DataSource dataSource; - - switch (provider) { - case MySQL: - MysqlDataSource mysqlDataSource = new MysqlDataSource(); - mysqlDataSource.setUrl(MYSQL_CONTAINER.getJdbcUrl()); - mysqlDataSource.setUser(MYSQL_CONTAINER.getUsername()); - mysqlDataSource.setPassword(MYSQL_CONTAINER.getPassword()); - dataSource = mysqlDataSource; - queryProvider = MySQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case PostgreSQL: - PGSimpleDataSource pgSimpleDataSource = new PGSimpleDataSource(); - pgSimpleDataSource.setUrl(POSTGRESQL_CONTAINER.getJdbcUrl()); - pgSimpleDataSource.setUser(POSTGRESQL_CONTAINER.getUsername()); - pgSimpleDataSource.setPassword(POSTGRESQL_CONTAINER.getPassword()); - dataSource = pgSimpleDataSource; - queryProvider = PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case SQLite: - Path sqliteDb = createTempDbFile("sqliteDb"); - SQLiteDataSource sqliteDataSource = new SQLiteDataSource(); - sqliteDataSource.setUrl("jdbc:sqlite:file:" + sqliteDb.toFile().getAbsolutePath()); - dataSource = sqliteDataSource; - - queryProvider = SQLiteVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case HSQLDB: - try { - Path file = createTempDbFile("testHSQLDB"); - - Properties properties = new Properties(); - properties.putAll( - Map.of( - "url", "jdbc:hsqldb:file:" + file.toFile().getAbsolutePath() - + ";sql.syntax_mys=true", - "user", "SA", - "password", "" - ) - ); - - dataSource = JDBCDataSourceFactory.createDataSource(properties); - } catch (Exception e) { - throw new RuntimeException(e); - } - - queryProvider = HSQLDBVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - default: - throw new IllegalArgumentException("Unknown query provider: " + provider); - } - - JDBCVectorStoreRecordCollection recordCollection = new JDBCVectorStoreRecordCollection<>( - dataSource, - collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withQueryProvider(queryProvider) - .build()); - - recordCollection.prepareAsync().block(); - recordCollection.createCollectionIfNotExistsAsync().block(); - return recordCollection; - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void buildRecordCollection(QueryProvider provider) { - assertNotNull(buildRecordCollection(provider, "buildTest")); - } - - private List getHotels() { - return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", - Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f), null, null, null, - 4.0, Arrays.asList("luxury", "city")), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", - Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f), null, null, null, - 4.0, Arrays.asList("luxury", "city")), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", - Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f), null, null, null, - 5.0, Arrays.asList("luxury", "beach")), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", - Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f), null, null, null, - 4.0, Arrays.asList("luxury", "city")), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", - Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f), null, null, null, - 4.0, Arrays.asList("luxury", "city")) - ); - } - - /** - * Search embeddings similar to the third hotel embeddings. In order of similarity: 1. Hotel 3 - * 2. Hotel 1 3. Hotel 4 - */ - private static final List SEARCH_EMBEDDINGS = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, - -0.8f, 1.1f, -2.2f, 8.2f); - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void upsertAndGetRecordAsync(QueryProvider provider) { - String collectionName = "upsertAndGetRecordAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - // Upsert the first time - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getRating(), retrievedHotel.getRating()); - - // Update the rating - hotel.setRating(1.0); - } - - // Upsert the second time with updated rating - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(1.0, retrievedHotel.getRating()); - } - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void getBatchAsync(QueryProvider provider) { - String collectionName = "getBatchAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - List keys = new ArrayList<>(); - for (Hotel hotel : hotels) { - keys.add(hotel.getId()); - } - - List retrievedHotels = recordCollection.getBatchAsync(keys, null).block(); - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void upsertBatchAndGetBatchAsync(QueryProvider provider) { - String collectionName = "upsertBatchAndGetBatchAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = new ArrayList<>(); - for (Hotel hotel : hotels) { - keys.add(hotel.getId()); - } - - List retrievedHotels = recordCollection.getBatchAsync(keys, null).block(); - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void insertAndReplaceAsync(QueryProvider provider) { - String collectionName = "insertAndReplaceAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - recordCollection.upsertBatchAsync(hotels, null).block(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = new ArrayList<>(); - for (Hotel hotel : hotels) { - keys.add(hotel.getId()); - } - - List retrievedHotels = recordCollection.getBatchAsync(keys, null).block(); - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void deleteRecordAsync(QueryProvider provider) { - String collectionName = "deleteRecordAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - recordCollection.deleteAsync(hotel.getId(), null).block(); - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void deleteBatchAsync(QueryProvider provider) { - String collectionName = "deleteBatchAsync"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = new ArrayList<>(); - for (Hotel hotel : hotels) { - keys.add(hotel.getId()); - } - - recordCollection.deleteBatchAsync(keys, null).block(); - - for (String key : keys) { - Hotel retrievedHotel = recordCollection.getAsync(key, null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void getWithNoVectors(QueryProvider provider) { - String collectionName = "getWithNoVectors"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions options = GetRecordOptions.builder() - .includeVectors(false) - .build(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), options).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertNull(retrievedHotel.getEuclidean()); - } - - options = GetRecordOptions.builder() - .includeVectors(true) - .build(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), options).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertNotNull(retrievedHotel.getEuclidean()); - } - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void getBatchWithNoVectors(QueryProvider provider) { - String collectionName = "getBatchWithNoVectors"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions options = GetRecordOptions.builder() - .includeVectors(false) - .build(); - - List keys = new ArrayList<>(); - for (Hotel hotel : hotels) { - keys.add(hotel.getId()); - } - - List retrievedHotels = recordCollection.getBatchAsync(keys, options).block(); - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - - for (Hotel hotel : retrievedHotels) { - assertNull(hotel.getEuclidean()); - } - - options = GetRecordOptions.builder() - .includeVectors(true) - .build(); - - retrievedHotels = recordCollection.getBatchAsync(keys, options).block(); - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - - for (Hotel hotel : retrievedHotels) { - assertNotNull(hotel.getEuclidean()); - } - } - - private static Stream provideSearchParameters() { - return Arrays.stream(QueryProvider.values()).map(provider -> - Stream.of( - Arguments.of(provider, "euclidean"), - Arguments.of(provider, "cosineDistance"), - Arguments.of(provider, "dotProduct") - ) - ).flatMap(s -> s); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void exactSearch(QueryProvider provider, String embeddingName) { - String collectionName = "search" + embeddingName; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId()); - - options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withSkip(1) - .withTop(-100) - .build(); - - // Skip the first result - results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(1, results.size()); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId()); - } - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void approximateSearch(QueryProvider provider) { - String collectionName = "searchWithIndex"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName("indexedEuclidean") - .withTop(5) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(5, results.size()); - // The third hotel should be the most similar - assertEquals("id_3", results.get(0).getRecord().getId()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithFilterEqualToFilter(QueryProvider provider, String embeddingName) { - String collectionName = "searchWithFilterEqualToFilter"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals("id_1", results.get(0).getRecord().getId()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithAnyTagEqualToFilter(QueryProvider provider, String embeddingName) { - String collectionName = "searchWithAnyTagEqualToFilter"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection(provider, - collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .anyTagEqualTo("tags", "city").build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals("id_1", results.get(0).getRecord().getId()); - } - - // MySQL will always return the vectors as they're needed to compute the distances - @Test - public void postgresSearchIncludeAndNotIncludeVectors() { - String collectionName = "searchIncludeAndNotIncludeVectors"; - JDBCVectorStoreRecordCollection recordCollection = buildRecordCollection( - QueryProvider.PostgreSQL, collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - null).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId()); - assertNull(results.get(0).getRecord().getEuclidean()); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withIncludeVectors(true) - .build(); - - results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The third hotel should be the most similar - assertEquals("id_3", results.get(0).getRecord().getId()); - assertNotNull(results.get(0).getRecord().getEuclidean()); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreTest.java deleted file mode 100644 index ce62c70d8..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/jdbc/JDBCVectorStoreTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.microsoft.semantickernel.tests.data.jdbc; - -import com.microsoft.semantickernel.data.jdbc.hsqldb.HSQLDBVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.mysql.MySQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.sqlite.SQLiteVectorStoreQueryProvider; -import com.mysql.cj.jdbc.MysqlDataSource; -import org.hsqldb.jdbc.JDBCDataSourceFactory; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.postgresql.ds.PGSimpleDataSource; -import org.sqlite.SQLiteDataSource; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import javax.sql.DataSource; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import com.microsoft.semantickernel.tests.data.jdbc.JDBCVectorStoreRecordCollectionTest.QueryProvider; - -import static com.microsoft.semantickernel.tests.data.jdbc.JDBCVectorStoreRecordCollectionTest.createTempDbFile; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Testcontainers -public class JDBCVectorStoreTest { - - @Container - private static final MySQLContainer MYSQL_CONTAINER = new MySQLContainer<>("mysql:5.7.34"); - - private static final DockerImageName PGVECTOR = DockerImageName.parse("pgvector/pgvector:pg16") - .asCompatibleSubstituteFor("postgres"); - @Container - private static final PostgreSQLContainer POSTGRESQL_CONTAINER = new PostgreSQLContainer<>( - PGVECTOR); - - private JDBCVectorStore buildVectorStore(QueryProvider provider) { - SQLVectorStoreQueryProvider queryProvider; - DataSource dataSource; - - switch (provider) { - case MySQL: - MysqlDataSource mysqlDataSource = new MysqlDataSource(); - mysqlDataSource.setUrl(MYSQL_CONTAINER.getJdbcUrl()); - mysqlDataSource.setUser(MYSQL_CONTAINER.getUsername()); - mysqlDataSource.setPassword(MYSQL_CONTAINER.getPassword()); - dataSource = mysqlDataSource; - queryProvider = MySQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case PostgreSQL: - PGSimpleDataSource pgSimpleDataSource = new PGSimpleDataSource(); - pgSimpleDataSource.setUrl(POSTGRESQL_CONTAINER.getJdbcUrl()); - pgSimpleDataSource.setUser(POSTGRESQL_CONTAINER.getUsername()); - pgSimpleDataSource.setPassword(POSTGRESQL_CONTAINER.getPassword()); - dataSource = pgSimpleDataSource; - queryProvider = PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case SQLite: - Path sqliteDb = createTempDbFile("testSQLite"); - SQLiteDataSource sqliteDataSource = new SQLiteDataSource(); - sqliteDataSource.setUrl("jdbc:sqlite:file:" + sqliteDb.toFile().getAbsolutePath()); - dataSource = sqliteDataSource; - - queryProvider = SQLiteVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - case HSQLDB: - try { - Path file = createTempDbFile("testHSQLDB"); - - Properties properties = new Properties(); - properties.putAll( - Map.of( - "url", "jdbc:hsqldb:file:" + file.toFile().getAbsolutePath() - + ";sql.syntax_mys=true", - "user", "SA", - "password", "" - ) - ); - - dataSource = JDBCDataSourceFactory.createDataSource(properties); - } catch (Exception e) { - throw new RuntimeException(e); - } - - queryProvider = HSQLDBVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - break; - default: - throw new IllegalArgumentException("Unknown query provider: " + provider); - } - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions( - JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build() - ) - .build(); - - vectorStore.prepareAsync().block(); - return vectorStore; - } - - - @ParameterizedTest - @EnumSource(QueryProvider.class) - public void getCollectionNamesAsync(QueryProvider provider) { - JDBCVectorStore vectorStore = buildVectorStore(provider); - - vectorStore.getCollectionNamesAsync().block(); - - List collectionNames = Arrays.asList("collection1", "collection2", "collection3"); - - for (String collectionName : collectionNames) { - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()).createCollectionAsync().block(); - } - - List retrievedCollectionNames = vectorStore.getCollectionNamesAsync().block(); - assertNotNull(retrievedCollectionNames); - assertEquals(collectionNames.size(), retrievedCollectionNames.size()); - for (String collectionName : collectionNames) { - assertTrue(retrievedCollectionNames.contains(collectionName)); - } - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java deleted file mode 100644 index 416e06b66..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.microsoft.semantickernel.tests.data.redis; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import java.util.List; - -public class Hotel { - - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final String name; - - @VectorStoreRecordData - private final int code; - - @JsonProperty("summary") - @VectorStoreRecordData() - private final String description; - - @JsonProperty("summaryEmbedding1") - @VectorStoreRecordVector(dimensions = 8, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.EUCLIDEAN_DISTANCE) - private final List euclidean; - - @JsonProperty("summaryEmbedding2") - @VectorStoreRecordVector(dimensions = 8) - private final List cosineDistance; - - @JsonProperty("summaryEmbedding3") - @VectorStoreRecordVector(dimensions = 8, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.DOT_PRODUCT) - private final List dotProduct; - - @VectorStoreRecordData(isFilterable = true) - private double rating; - - public Hotel() { - this(null, null, 0, null, null, null, null, 0.0); - } - - @JsonCreator - public Hotel( - @JsonProperty("id") String id, - @JsonProperty("name") String name, - @JsonProperty("code") int code, - @JsonProperty("summary") String description, - @JsonProperty("summaryEmbedding1") List euclidean, - @JsonProperty("summaryEmbedding2") List cosineDistance, - @JsonProperty("summaryEmbedding3") List dotProduct, - @JsonProperty("rating") double rating) { - this.id = id; - this.name = name; - this.code = code; - this.description = description; - this.euclidean = euclidean; - this.cosineDistance = euclidean; - this.dotProduct = euclidean; - this.rating = rating; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public int getCode() { - return code; - } - - public String getDescription() { - return description; - } - - public List getEuclidean() { - return euclidean; - } - - public List getCosineDistance() { - return cosineDistance; - } - - public List getDotProduct() { - return dotProduct; - } - - public double getRating() { - return rating; - } - - public void setRating(double rating) { - this.rating = rating; - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java deleted file mode 100644 index c5b6a186f..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,471 +0,0 @@ -package com.microsoft.semantickernel.tests.data.redis; - -import com.microsoft.semantickernel.data.redis.RedisHashSetVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.redis.RedisHashSetVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.redis.testcontainers.RedisContainer; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.MethodSource; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import redis.clients.jedis.JedisPooled; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; - -@Testcontainers -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class RedisHashSetVectorStoreRecordCollectionTest { - - @Container private static final RedisContainer redisContainer = new RedisContainer("redis/redis-stack:latest"); - - private static final Map> optionsMap = new HashMap<>(); - - public enum RecordCollectionOptions { - DEFAULT, WITH_CUSTOM_DEFINITION - } - - @BeforeAll - static void setup() { - optionsMap.put(RecordCollectionOptions.DEFAULT, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - List fields = new ArrayList<>(); - fields.add(VectorStoreRecordKeyField.builder() - .withName("id") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("name") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("code") - .withFieldType(Integer.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("description") - .withStorageName("summary") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("euclidean") - .withStorageName("summaryEmbedding1") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("cosineDistance") - .withStorageName("summaryEmbedding2") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("dotProduct") - .withStorageName("summaryEmbedding3") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("rating") - .withFieldType(Double.class) - .isFilterable(true) - .build()); - VectorStoreRecordDefinition recordDefinition = VectorStoreRecordDefinition.fromFields(fields); - - optionsMap.put(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withRecordDefinition(recordDefinition) - .build()); - - // Search configuration - List hotels = getHotels(); - - for (RecordCollectionOptions options : RecordCollectionOptions.values()) { - String collectionName = getCollectionName("search", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - - recordCollection.upsertBatchAsync(hotels, null).block(); - } - - // Wait for data to be indexed - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - private static RedisHashSetVectorStoreRecordCollection createCollection(@Nonnull RedisHashSetVectorStoreRecordCollectionOptions options, @Nonnull String collectionName) { - return new RedisHashSetVectorStoreRecordCollection<>(new JedisPooled(redisContainer.getRedisURI()), collectionName, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(options.getRecordClass()) - .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) - .withRecordDefinition(options.getRecordDefinition()) - .withPrefixCollectionName(options.isPrefixCollectionName()) - .build()); - } - - private static List getHotels() { - return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) - ); - } - - /** - * Search embeddings similar to the third hotel embeddings. - * In order of similarity: - * 1. Hotel 3 - * 2. Hotel 1 - * 3. Hotel 4 - */ - private static final List SEARCH_EMBEDDINGS = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.2f); - - private static String getCollectionName(String id, RecordCollectionOptions options) { - return id + options.name(); - } - - @Order(1) - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void createCollectionAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("createCollectionAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - assertEquals(false, recordCollection.collectionExistsAsync().block()); - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - } - - @Test - public void deleteCollectionAsync() { - String collectionName = getCollectionName("deleteCollectionAsync", RecordCollectionOptions.DEFAULT); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(RecordCollectionOptions.DEFAULT), collectionName); - - assertEquals(false, recordCollection.collectionExistsAsync().block()); - recordCollection.createCollectionAsync().block(); - recordCollection.deleteCollectionAsync().block(); - assertEquals(false, recordCollection.collectionExistsAsync().block()); - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void upsertAndGetRecordAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("upsertAndGetRecordAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, new GetRecordOptions(true)).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void upsertBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("upsertBatchAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - List keys = recordCollection.upsertBatchAsync(hotels, null).block(); - assertNotNull(keys); - - List retrievedHotels = (List) recordCollection.getBatchAsync(keys, null).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void deleteAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("deleteAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - recordCollection.deleteAsync(hotel.getId(), null).block(); - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void deleteBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("deleteBatchAsync", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - recordCollection.deleteBatchAsync(ids, null).block(); - - for (String id : ids) { - Hotel retrievedHotel = recordCollection.getAsync(id, null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getAsyncWithVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getAsyncWithVectors", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), new GetRecordOptions(true)).block(); - assertNotNull(retrievedHotel); - assertNotNull(retrievedHotel.getEuclidean()); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsyncWithVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsyncWithVectors", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, new GetRecordOptions(true)).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - assertEquals(hotels.get(i).getDescription(), retrievedHotels.get(i).getDescription()); - assertNotNull(retrievedHotels.get(i).getEuclidean()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getAsyncWithNoVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getAsyncWithNoVectors", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions getRecordOptions = GetRecordOptions.builder().includeVectors(false).build(); - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), getRecordOptions).block(); - assertNotNull(retrievedHotel); - assertNull(retrievedHotel.getEuclidean()); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsyncWithNoVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsyncWithNoVectors", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions getRecordOptions = GetRecordOptions.builder().includeVectors(false).build(); - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, getRecordOptions).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - assertEquals(hotels.get(i).getDescription(), retrievedHotels.get(i).getDescription()); - assertNull(retrievedHotels.get(i).getEuclidean()); - } - } - - private static Stream provideSearchParameters() { - return Stream.of( - Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), - Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), - Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") - ); - } - - private final String indexingFailureMessage = "If you are running in a slow machine, data might not be indexed yet. Adjust setup delay if needed"; - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void search(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(VectorSearchOptions.DEFAULT_TOP, results.size(), indexingFailureMessage); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - // Score should be different than zero - assertNotEquals(0.0, results.get(0).getScore()); - assertNull(results.get(0).getRecord().getEuclidean()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithVectors(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withIncludeVectors(true) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(VectorSearchOptions.DEFAULT_TOP, results.size(), indexingFailureMessage); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - assertNotNull(results.get(0).getRecord().getEuclidean()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithOffSet(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withSkip(1) - .withTop(4) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(4, results.size(), indexingFailureMessage); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithFilterEqualToFilter(RecordCollectionOptions recordCollectionOptions, String embeddingName) { - String collectionName = getCollectionName("search", recordCollectionOptions); - RedisHashSetVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(recordCollectionOptions), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals("id_1", results.get(0).getRecord().getId()); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java deleted file mode 100644 index 1b4c30e82..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,471 +0,0 @@ -package com.microsoft.semantickernel.tests.data.redis; - -import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.redis.testcontainers.RedisContainer; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.MethodSource; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import redis.clients.jedis.JedisPooled; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; - -@Testcontainers -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class RedisJsonVectorStoreRecordCollectionTest { - - @Container private static final RedisContainer redisContainer = new RedisContainer("redis/redis-stack:latest"); - - private static final Map> optionsMap = new HashMap<>(); - - public enum RecordCollectionOptions { - DEFAULT, WITH_CUSTOM_DEFINITION - } - - @BeforeAll - static void setup() { - optionsMap.put(RecordCollectionOptions.DEFAULT, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - List fields = new ArrayList<>(); - fields.add(VectorStoreRecordKeyField.builder() - .withName("id") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("name") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("code") - .withFieldType(Integer.class) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("description") - .withStorageName("summary") - .withFieldType(String.class) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("euclidean") - .withStorageName("summaryEmbedding1") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("cosineDistance") - .withStorageName("summaryEmbedding2") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordVectorField.builder() - .withName("dotProduct") - .withStorageName("summaryEmbedding3") - .withFieldType(List.class) - .withDimensions(8) - .build()); - fields.add(VectorStoreRecordDataField.builder() - .withName("rating") - .withFieldType(Double.class) - .isFilterable(true) - .build()); - VectorStoreRecordDefinition recordDefinition = VectorStoreRecordDefinition.fromFields(fields); - - optionsMap.put(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withRecordDefinition(recordDefinition) - .build()); - - // Search configuration - List hotels = getHotels(); - - for (RecordCollectionOptions options : RecordCollectionOptions.values()) { - String collectionName = getCollectionName("search", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - - recordCollection.upsertBatchAsync(hotels, null).block(); - } - - // Wait for data to be indexed - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - private static RedisJsonVectorStoreRecordCollection createCollection(@Nonnull RedisJsonVectorStoreRecordCollectionOptions options, @Nonnull String collectionName) { - return new RedisJsonVectorStoreRecordCollection<>(new JedisPooled(redisContainer.getRedisURI()), collectionName, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(options.getRecordClass()) - .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) - .withRecordDefinition(options.getRecordDefinition()) - .withPrefixCollectionName(options.isPrefixCollectionName()) - .build()); - } - - private static List getHotels() { - return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) - ); - } - - /** - * Search embeddings similar to the third hotel embeddings. - * In order of similarity: - * 1. Hotel 3 - * 2. Hotel 1 - * 3. Hotel 4 - */ - private static final List SEARCH_EMBEDDINGS = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.2f); - - private static String getCollectionName(String id, RecordCollectionOptions options) { - return id + options.name(); - } - - @Order(1) - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void createCollectionAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("createCollectionAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - assertEquals(false, recordCollection.collectionExistsAsync().block()); - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - } - - @Test - public void deleteCollectionAsync() { - String collectionName = getCollectionName("deleteCollectionAsync", RecordCollectionOptions.DEFAULT); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(RecordCollectionOptions.DEFAULT), collectionName); - - assertEquals(false, recordCollection.collectionExistsAsync().block()); - recordCollection.createCollectionAsync().block(); - recordCollection.deleteCollectionAsync().block(); - assertEquals(false, recordCollection.collectionExistsAsync().block()); - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void upsertAndGetRecordAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("upsertAndGetRecordAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, new GetRecordOptions(true)).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void upsertBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("upsertBatchAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - List keys = recordCollection.upsertBatchAsync(hotels, null).block(); - assertNotNull(keys); - - List retrievedHotels = (List) recordCollection.getBatchAsync(keys, null).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void deleteAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("deleteAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - recordCollection.deleteAsync(hotel.getId(), null).block(); - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void deleteBatchAsync(RecordCollectionOptions options) { - String collectionName = getCollectionName("deleteBatchAsync", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - recordCollection.deleteBatchAsync(ids, null).block(); - - for (String id : ids) { - Hotel retrievedHotel = recordCollection.getAsync(id, null).block(); - assertNull(retrievedHotel); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getAsyncWithVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getAsyncWithVectors", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), new GetRecordOptions(true)).block(); - assertNotNull(retrievedHotel); - assertNotNull(retrievedHotel.getEuclidean()); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsyncWithVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsyncWithVectors", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, new GetRecordOptions(true)).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - assertEquals(hotels.get(i).getDescription(), retrievedHotels.get(i).getDescription()); - assertNotNull(retrievedHotels.get(i).getEuclidean()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getAsyncWithNoVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getAsyncWithNoVectors", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions getRecordOptions = GetRecordOptions.builder().includeVectors(false).build(); - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), getRecordOptions).block(); - assertNotNull(retrievedHotel); - assertNull(retrievedHotel.getEuclidean()); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @ParameterizedTest - @EnumSource(RecordCollectionOptions.class) - public void getBatchAsyncWithNoVectors(RecordCollectionOptions options) { - String collectionName = getCollectionName("getBatchAsyncWithNoVectors", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - GetRecordOptions getRecordOptions = GetRecordOptions.builder().includeVectors(false).build(); - List ids = new ArrayList<>(); - hotels.forEach(hotel -> ids.add(hotel.getId())); - - List retrievedHotels = recordCollection.getBatchAsync(ids, getRecordOptions).block(); - - assertNotNull(retrievedHotels); - assertEquals(hotels.size(), retrievedHotels.size()); - for (int i = 0; i < hotels.size(); i++) { - assertEquals(hotels.get(i).getId(), retrievedHotels.get(i).getId()); - assertEquals(hotels.get(i).getDescription(), retrievedHotels.get(i).getDescription()); - assertNull(retrievedHotels.get(i).getEuclidean()); - } - } - - private static Stream provideSearchParameters() { - return Stream.of( - Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), - Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), - Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") - ); - } - - private final String indexingFailureMessage = "If you are running in a slow machine, data might not be indexed yet. Adjust setup delay if needed"; - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void search(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(VectorSearchOptions.DEFAULT_TOP, results.size(), indexingFailureMessage); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - // Score should be different than zero - assertNotEquals(0.0, results.get(0).getScore()); - assertNull(results.get(0).getRecord().getEuclidean()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithVectors(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withIncludeVectors(true) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(VectorSearchOptions.DEFAULT_TOP, results.size(), indexingFailureMessage); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - assertNotNull(results.get(0).getRecord().getEuclidean()); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithOffSet(RecordCollectionOptions options, String embeddingName) { - String collectionName = getCollectionName("search", options); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(options), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withSkip(1) - .withTop(4) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); - assertNotNull(results); - assertEquals(4, results.size(), indexingFailureMessage); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId(), indexingFailureMessage); - } - - @ParameterizedTest - @MethodSource("provideSearchParameters") - public void searchWithFilterEqualToFilter(RecordCollectionOptions recordCollectionOptions, String embeddingName) { - String collectionName = getCollectionName("search", recordCollectionOptions); - RedisJsonVectorStoreRecordCollection recordCollection = createCollection(optionsMap.get(recordCollectionOptions), collectionName); - - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals("id_1", results.get(0).getRecord().getId()); - } -} diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisVectorStoreTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisVectorStoreTest.java deleted file mode 100644 index 93ee1c205..000000000 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisVectorStoreTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.microsoft.semantickernel.tests.data.redis; - -import com.microsoft.semantickernel.data.redis.RedisHashSetVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.redis.RedisStorageType; -import com.microsoft.semantickernel.data.redis.RedisVectorStore; -import com.microsoft.semantickernel.data.redis.RedisVectorStoreOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.redis.testcontainers.RedisContainer; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import redis.clients.jedis.JedisPooled; - -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Testcontainers -public class RedisVectorStoreTest { - @Container - private static final RedisContainer redisJsonContainer = new RedisContainer("redis/redis-stack:latest"); - @Container - private static final RedisContainer redisHashSetContainer = new RedisContainer("redis/redis-stack:latest"); - - public static JedisPooled buildClient(RedisStorageType storageType) { - if (storageType == RedisStorageType.JSON) { - return new JedisPooled(redisJsonContainer.getRedisURI()); - } else { - return new JedisPooled(redisHashSetContainer.getRedisURI()); - } - } - - private static VectorStoreRecordCollectionOptions getRecordCollectionOptions(RedisStorageType storageType) { - if (storageType == RedisStorageType.JSON) { - return RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build(); - } else { - return RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build(); - } - } - - @ParameterizedTest - @EnumSource(RedisStorageType.class) - public void getCollectionNamesAsync(RedisStorageType storageType) { - RedisVectorStore vectorStore = new RedisVectorStore(buildClient(storageType), RedisVectorStoreOptions.builder() - .withStorageType(storageType) - .build()); - - List collectionNames = Arrays.asList("collection1", "collection2", "collection3"); - - for (String collectionName : collectionNames) { - vectorStore.getCollection(collectionName, getRecordCollectionOptions(storageType)).createCollectionAsync().block(); - } - - List retrievedCollectionNames = vectorStore.getCollectionNamesAsync().block(); - assertNotNull(retrievedCollectionNames); - assertEquals(collectionNames.size(), retrievedCollectionNames.size()); - for (String collectionName : collectionNames) { - assertTrue(retrievedCollectionNames.contains(collectionName)); - } - } -} diff --git a/api-test/integration-tests/src/test/resources/log4j2.xml b/api-test/integration-tests/src/test/resources/log4j2.xml deleted file mode 100644 index 02e288f80..000000000 --- a/api-test/integration-tests/src/test/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/api-test/integration-tests/src/test/resources/responseSchema.prompt.yaml b/api-test/integration-tests/src/test/resources/responseSchema.prompt.yaml deleted file mode 100644 index 08fa066a8..000000000 --- a/api-test/integration-tests/src/test/resources/responseSchema.prompt.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: testResponseSchema -description: Test Response Schema -template: | - Do something -template_format: handlebars -execution_settings: - default: - max_tokens: 10 - temperature: 0.2 - response_format: - type: json_schema - json_schema: - name: Test - strict: true - schema: | - { - "type" : "object", - "properties" : { - "name" : { - "type" : "string" - } - }, - "required" : [ - "name" - ], - "additionalProperties" : false - } diff --git a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-12b6744e-443f-4fe7-82e2-55cc41195ff1.json b/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-12b6744e-443f-4fe7-82e2-55cc41195ff1.json deleted file mode 100644 index 4b27e3ba0..000000000 --- a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-12b6744e-443f-4fe7-82e2-55cc41195ff1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "priority": 1, - "request": { - "method": "POST", - "url": "//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2025-01-01-preview", - "bodyPatterns": [ - { - "contains": "That is all" - } - ] - }, - "response": { - "body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253061,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"EndConversation\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":17,\"completion_tokens\":67,\"total_tokens\":84}}", - "headers": {}, - "status": 200 - } -} diff --git a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-71b07779-49a8-44e5-a60b-ee5b0a3ad697.json b/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-71b07779-49a8-44e5-a60b-ee5b0a3ad697.json deleted file mode 100644 index 208f334c1..000000000 --- a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo-2_chat_completions-71b07779-49a8-44e5-a60b-ee5b0a3ad697.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "request": { - "method": "POST", - "url": "//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2025-01-01-preview" - }, - "response": { - "body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253061,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"1979b4ce-5463-4cfb-8ec8-1d05c4b44ccf\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":17,\"completion_tokens\":67,\"total_tokens\":84}}", - "headers": {}, - "status": 200 - } -} diff --git a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo_chat_completions-0c8046c5-74ad-4836-8aa9-09da60f367a2.json b/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo_chat_completions-0c8046c5-74ad-4836-8aa9-09da60f367a2.json deleted file mode 100644 index 766450c6e..000000000 --- a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_gpt-35-turbo_chat_completions-0c8046c5-74ad-4836-8aa9-09da60f367a2.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "request": { - "method": "POST", - "url": "//openai/deployments/gpt-35-turbo/chat/completions?api-version=2025-01-01-preview" - }, - "response": { - "body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253039,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"ac9817bc-7e1a-48e4-b06c-0ff7618b88c6\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":26,\"completion_tokens\":131,\"total_tokens\":157}}", - "headers": {}, - "status": 200 - } -} diff --git a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_text-davinci-003_completions-0215b128-4822-4368-ac3d-2f580a221f00.json b/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_text-davinci-003_completions-0215b128-4822-4368-ac3d-2f580a221f00.json deleted file mode 100644 index 56bccb38d..000000000 --- a/api-test/integration-tests/src/test/resources/wiremock/mappings/deployments_text-davinci-003_completions-0215b128-4822-4368-ac3d-2f580a221f00.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "request": { - "method": "POST", - "url": "//openai/deployments/text-davinci-003/completions?api-version=2025-01-01-preview" - }, - "response": { - "body": "{\"id\":\"cmpl-xxx\",\"object\":\"text_completion\",\"created\":1707253062,\"model\":\"text-davinci-003\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"text\":\"7949e981-c632-422f-9b76-335a2379cd83\",\"index\":0,\"finish_reason\":\"stop\",\"logprobs\":null,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":10,\"completion_tokens\":26,\"total_tokens\":36}}", - "headers": {}, - "status": 200 - } -} diff --git a/api-test/pom.xml b/api-test/pom.xml deleted file mode 100644 index 587dfe5b1..000000000 --- a/api-test/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - 4.0.0 - - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - Semantic Kernel Api Tests - api-test - pom - - - 3.11.0 - 17 - - - - integration-tests - - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - import - pom - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler-plugin.version} - - ${maven.compiler.release} - ${maven.compiler.release} - ${maven.compiler.release} - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - com.diffplug.spotless - spotless-maven-plugin - ${maven.spotless-plugin.version} - - true - - - - - - \ No newline at end of file diff --git a/api-test/spotbugs-exclude.xml b/api-test/spotbugs-exclude.xml deleted file mode 100644 index 5fd588b2c..000000000 --- a/api-test/spotbugs-exclude.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/data/semantickernel-data-azureaisearch/pom.xml b/data/semantickernel-data-azureaisearch/pom.xml deleted file mode 100644 index e9db7daae..000000000 --- a/data/semantickernel-data-azureaisearch/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-data-azureaisearch - Semantic Kernel Azure AI Search connector - Azure AI Search connector for Semantic Kernel - - - - com.azure - azure-ai-openai - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - - com.azure - azure-search-documents - - - com.azure - azure-core-serializer-json-jackson - - - - - - \ No newline at end of file diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStore.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStore.java deleted file mode 100644 index 66dbb3c6b..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStore.java +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.azure.search.documents.indexes.SearchIndexAsyncClient; -import com.azure.search.documents.indexes.models.SearchIndex; -import com.microsoft.semantickernel.data.vectorstorage.VectorStore; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -/** - * Represents an Azure AI Search vector store. - */ -public class AzureAISearchVectorStore implements VectorStore { - - private final SearchIndexAsyncClient searchIndexAsyncClient; - private final AzureAISearchVectorStoreOptions options; - - /** - * Creates a new instance of {@link AzureAISearchVectorStore}. - * - * @param searchIndexAsyncClient The Azure AI Search client. - * @param options The options for the vector store. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public AzureAISearchVectorStore(@Nonnull SearchIndexAsyncClient searchIndexAsyncClient, - @Nullable AzureAISearchVectorStoreOptions options) { - this.searchIndexAsyncClient = searchIndexAsyncClient; - this.options = options == null ? new AzureAISearchVectorStoreOptions() : options; - } - - /** - * Gets a new instance of {@link AzureAISearchVectorStoreRecordCollection} - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - * @return The collection. - */ - @Override - public final VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull VectorStoreRecordCollectionOptions options) { - if (!options.getKeyClass().equals(String.class)) { - throw new SKException("Azure AI Search only supports string keys"); - } - if (options.getRecordClass() == null) { - throw new SKException("Record class is required"); - } - - if (this.options.getVectorStoreRecordCollectionFactory() != null) { - return (VectorStoreRecordCollection) this.options - .getVectorStoreRecordCollectionFactory() - .createVectorStoreRecordCollection( - searchIndexAsyncClient, - collectionName, - options.getRecordClass(), - options.getRecordDefinition()); - } - - return (VectorStoreRecordCollection) new AzureAISearchVectorStoreRecordCollection<>( - searchIndexAsyncClient, - collectionName, - (AzureAISearchVectorStoreRecordCollectionOptions) options); - } - - /** - * Gets the names of all collections in the Azure AI Search vector store. - * - * @return A list of collection names. - */ - @Override - public Mono> getCollectionNamesAsync() { - return searchIndexAsyncClient.listIndexes().map(SearchIndex::getName).collectList(); - } - - /** - * Creates a new {@link Builder} instance. - * - * @return The new builder instance. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for {@link AzureAISearchVectorStore}. - */ - public static class Builder { - - @Nullable - private SearchIndexAsyncClient searchIndexAsyncClient; - @Nullable - private AzureAISearchVectorStoreOptions options; - - /** - * Sets the Azure AI Search searchIndexClient. - * - * @param searchIndexAsyncClient The Azure AI Search searchIndexClient. - * @return The updated builder instance. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withSearchIndexAsyncClient( - @Nonnull SearchIndexAsyncClient searchIndexAsyncClient) { - this.searchIndexAsyncClient = searchIndexAsyncClient; - return this; - } - - /** - * Sets the options for the Azure AI Search vector store. - * - * @param options The options for the Azure AI Search vector store. - * @return The updated builder instance. - */ - public Builder withOptions( - @Nonnull AzureAISearchVectorStoreOptions options) { - this.options = options; - return this; - } - - /** - * Builds the Azure AI Search vector store. - * - * @return The Azure AI Search vector store. - */ - public AzureAISearchVectorStore build() { - if (searchIndexAsyncClient == null) { - throw new SKException("searchIndexAsyncClient is required"); - } - - return new AzureAISearchVectorStore(searchIndexAsyncClient, options); - } - } -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionCreateMapping.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionCreateMapping.java deleted file mode 100644 index 1b12b0ade..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionCreateMapping.java +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.azure.search.documents.indexes.models.ExhaustiveKnnAlgorithmConfiguration; -import com.azure.search.documents.indexes.models.ExhaustiveKnnParameters; -import com.azure.search.documents.indexes.models.HnswAlgorithmConfiguration; -import com.azure.search.documents.indexes.models.HnswParameters; -import com.azure.search.documents.indexes.models.SearchField; -import com.azure.search.documents.indexes.models.SearchFieldDataType; -import com.azure.search.documents.indexes.models.VectorSearchAlgorithmConfiguration; -import com.azure.search.documents.indexes.models.VectorSearchAlgorithmMetric; -import com.azure.search.documents.indexes.models.VectorSearchProfile; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.exceptions.SKException; - -import java.time.OffsetDateTime; -import java.util.List; -import javax.annotation.Nonnull; - -/** - * Maps vector store record fields to Azure AI Search fields. - */ -class AzureAISearchVectorStoreCollectionCreateMapping { - - private static String getVectorSearchProfileName(VectorStoreRecordVectorField vectorField) { - return vectorField.getEffectiveStorageName() + "Profile"; - } - - private static String getAlgorithmConfigName(VectorStoreRecordVectorField vectorField) { - return vectorField.getEffectiveStorageName() + "AlgorithmConfig"; - } - - private static VectorSearchAlgorithmMetric getAlgorithmMetric( - @Nonnull VectorStoreRecordVectorField vectorField) { - if (vectorField.getDistanceFunction() == DistanceFunction.UNDEFINED) { - return VectorSearchAlgorithmMetric.COSINE; - } - - switch (vectorField.getDistanceFunction()) { - case COSINE_SIMILARITY: - return VectorSearchAlgorithmMetric.COSINE; - case DOT_PRODUCT: - return VectorSearchAlgorithmMetric.DOT_PRODUCT; - case EUCLIDEAN_DISTANCE: - return VectorSearchAlgorithmMetric.EUCLIDEAN; - default: - throw new SKException( - "Unsupported distance function: " + vectorField.getDistanceFunction()); - } - } - - private static VectorSearchAlgorithmConfiguration getAlgorithmConfig( - @Nonnull VectorStoreRecordVectorField vectorField) { - if (vectorField.getIndexKind() == IndexKind.UNDEFINED) { - return new HnswAlgorithmConfiguration(getAlgorithmConfigName(vectorField)) - .setParameters(new HnswParameters().setMetric(getAlgorithmMetric(vectorField))); - } - - switch (vectorField.getIndexKind()) { - case HNSW: - return new HnswAlgorithmConfiguration(getAlgorithmConfigName(vectorField)) - .setParameters(new HnswParameters().setMetric(getAlgorithmMetric(vectorField))); - case FLAT: - return new ExhaustiveKnnAlgorithmConfiguration(getAlgorithmConfigName(vectorField)) - .setParameters( - new ExhaustiveKnnParameters().setMetric(getAlgorithmMetric(vectorField))); - default: - throw new SKException( - "Unsupported index kind: " + vectorField.getIndexKind()); - } - } - - /** - * Maps a key field to a search field. - * - * @param keyField The key field. - * @return The search field. - */ - public static SearchField mapKeyField(VectorStoreRecordKeyField keyField) { - return new SearchField(keyField.getEffectiveStorageName(), SearchFieldDataType.STRING) - .setKey(true) - .setFilterable(true); - } - - /** - * Maps a data field to a search field. - * - * @param dataField The data field. - * @return The search field. - */ - public static SearchField mapDataField(VectorStoreRecordDataField dataField) { - if (dataField.getFieldType() == null) { - throw new SKException( - "Field type is required: " + dataField.getEffectiveStorageName()); - } - - return new SearchField(dataField.getEffectiveStorageName(), - getSearchFieldDataType(dataField.getFieldType())) - .setFilterable(dataField.isFilterable()) - .setSearchable(dataField.isFullTextSearchable()); - } - - /** - * Maps a vector field to a search field. - * - * @param vectorField The vector field. - * @return The search field. - */ - public static SearchField mapVectorField(VectorStoreRecordVectorField vectorField) { - return new SearchField(vectorField.getEffectiveStorageName(), - SearchFieldDataType.collection(SearchFieldDataType.SINGLE)) - .setSearchable(true) - .setVectorSearchDimensions(vectorField.getDimensions()) - .setVectorSearchProfileName(getVectorSearchProfileName(vectorField)); - } - - /** - * Updates the vector search parameters for the specified vector field. - * - * @param algorithms The list of vector search algorithms. - * @param profiles The list of vector search profiles. - * @param vectorField The vector field. - */ - public static void updateVectorSearchParameters( - List algorithms, - List profiles, - VectorStoreRecordVectorField vectorField) { - if (vectorField.getDimensions() <= 0) { - throw new SKException("Vector field dimensions must be greater than 0"); - } - - algorithms.add(getAlgorithmConfig(vectorField)); - profiles.add(new VectorSearchProfile( - getVectorSearchProfileName(vectorField), getAlgorithmConfigName(vectorField))); - } - - /** - * Gets the search field data type for the specified field type. - * - * @param fieldType The field type. - * @return The search field data type. - */ - public static SearchFieldDataType getSearchFieldDataType(Class fieldType) { - if (fieldType == String.class) { - return SearchFieldDataType.STRING; - } else if (fieldType == Integer.class || fieldType == int.class) { - return SearchFieldDataType.INT32; - } else if (fieldType == Long.class || fieldType == long.class) { - return SearchFieldDataType.INT64; - } else if (fieldType == Float.class || fieldType == float.class) { - return SearchFieldDataType.DOUBLE; - } else if (fieldType == Double.class || fieldType == double.class) { - return SearchFieldDataType.DOUBLE; - } else if (fieldType == Boolean.class || fieldType == boolean.class) { - return SearchFieldDataType.BOOLEAN; - } else if (fieldType == OffsetDateTime.class) { - return SearchFieldDataType.DATE_TIME_OFFSET; - } else { - throw new SKException("Unsupported field type: " + fieldType.getName()); - } - } -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java deleted file mode 100644 index c31af301d..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.filter.FilterMapping; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; - -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.util.stream.Collectors; - -class AzureAISearchVectorStoreCollectionSearchMapping - implements FilterMapping { - - private AzureAISearchVectorStoreCollectionSearchMapping() { - } - - private static class AzureAISearchVectorStoreCollectionSearchMappingHolder { - private static final AzureAISearchVectorStoreCollectionSearchMapping INSTANCE = new AzureAISearchVectorStoreCollectionSearchMapping(); - } - - static AzureAISearchVectorStoreCollectionSearchMapping getInstance() { - return AzureAISearchVectorStoreCollectionSearchMappingHolder.INSTANCE; - } - - public String getFilter(VectorSearchFilter vectorSearchFilter, - VectorStoreRecordDefinition recordDefinition) { - if (vectorSearchFilter == null - || vectorSearchFilter.getFilterClauses().isEmpty()) { - return ""; - } - - return vectorSearchFilter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - // Create new instance with the storage name of the field - return getEqualToFilter(new EqualToFilterClause( - recordDefinition.getField(equalToFilterClause.getFieldName()) - .getEffectiveStorageName(), - equalToFilterClause.getValue())); - } else if (filterClause instanceof AnyTagEqualToFilterClause) { - AnyTagEqualToFilterClause anyTagEqualToFilterClause = (AnyTagEqualToFilterClause) filterClause; - // Create new instance with the storage name of the field - return getAnyTagEqualToFilter(new AnyTagEqualToFilterClause( - recordDefinition.getField(anyTagEqualToFilterClause.getFieldName()) - .getEffectiveStorageName(), - anyTagEqualToFilterClause.getValue())); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.joining(" and ")); - } - - @Override - public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = filterClause.getFieldName(); - Object value = filterClause.getValue(); - - if (value instanceof String) { - return String.format("%s eq '%s'", fieldName, value); - } else if (value instanceof Boolean) { - return String.format("%s eq %s", fieldName, - value.toString().toLowerCase()); - } else if (value instanceof Integer) { - return String.format("%s eq %d", fieldName, (Integer) value); - } else if (value instanceof Long) { - return String.format("%s eq %d", fieldName, (Long) value); - } else if (value instanceof Float) { - return String.format("%s eq %f", fieldName, (Float) value); - } else if (value instanceof Double) { - return String.format("%s eq %f", fieldName, (Double) value); - } else if (value instanceof OffsetDateTime) { - return String.format("%s eq %s", fieldName, ((OffsetDateTime) value) - .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); - } else if (value == null) { - return String.format("%s eq null", fieldName); - } else { - throw new SKException("Unsupported filter value type '" - + value.getClass().getSimpleName() + "'."); - } - } - - @Override - public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - return String.format("%s/any(t: t eq '%s')", filterClause.getFieldName(), - filterClause.getValue()); - } -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreOptions.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreOptions.java deleted file mode 100644 index 23e907f2f..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreOptions.java +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import javax.annotation.Nullable; - -/** - * Represents the options for the Azure AI Search vector store. - */ -public class AzureAISearchVectorStoreOptions { - - @Nullable - private final AzureAISearchVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - - /** - * Creates a new instance of the Azure AI Search vector store options. - * - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - */ - public AzureAISearchVectorStoreOptions( - @Nullable AzureAISearchVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - } - - /** - * Creates a new instance of the Azure AI Search vector store options. - */ - public AzureAISearchVectorStoreOptions() { - this(null); - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Gets the vector store record collection factory. - * - * @return the vector store record collection factory - */ - @Nullable - public AzureAISearchVectorStoreRecordCollectionFactory getVectorStoreRecordCollectionFactory() { - return vectorStoreRecordCollectionFactory; - } - - /** - * Builder for Azure AI Search vector store options. - * - */ - public static class Builder { - - @Nullable - private AzureAISearchVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - - /** - * Sets the vector store record collection factory. - * - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - * @return The updated builder instance. - */ - public Builder withVectorStoreRecordCollectionFactory( - AzureAISearchVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - return this; - } - - /** - * Builds the Azure AI Search vector store options. - * - * @return The Azure AI Search vector store options. - */ - public AzureAISearchVectorStoreOptions build() { - return new AzureAISearchVectorStoreOptions(vectorStoreRecordCollectionFactory); - } - } -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollection.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollection.java deleted file mode 100644 index b1c15b82f..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollection.java +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.azure.search.documents.SearchAsyncClient; -import com.azure.search.documents.SearchDocument; -import com.azure.search.documents.indexes.SearchIndexAsyncClient; -import com.azure.search.documents.indexes.models.SearchField; -import com.azure.search.documents.indexes.models.SearchIndex; -import com.azure.search.documents.indexes.models.VectorSearchAlgorithmConfiguration; -import com.azure.search.documents.indexes.models.VectorSearchProfile; -import com.azure.search.documents.models.IndexDocumentsResult; -import com.azure.search.documents.models.IndexingResult; -import com.azure.search.documents.models.ScoringParameter; -import com.azure.search.documents.models.SearchOptions; -import com.azure.search.documents.models.VectorQuery; -import com.azure.search.documents.models.VectorizableTextQuery; -import com.azure.search.documents.models.VectorizedQuery; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorsearch.VectorizableTextSearch; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * Represents an Azure AI Search vector store record collection. - * - * @param The type of the record. - */ -public class AzureAISearchVectorStoreRecordCollection implements - VectorStoreRecordCollection, - VectorizedSearch, - VectorizableTextSearch { - - private static final HashSet> supportedKeyTypes = new HashSet<>( - Collections.singletonList( - String.class)); - - private static final HashSet> supportedDataTypes = new HashSet<>( - Arrays.asList( - String.class, - Integer.class, - int.class, - Long.class, - long.class, - Float.class, - float.class, - Double.class, - double.class, - Boolean.class, - boolean.class, - OffsetDateTime.class, - List.class)); - - private static final HashSet> supportedVectorTypes = new HashSet<>( - Arrays.asList( - List.class, - Collection.class)); - - private final SearchIndexAsyncClient searchIndexAsyncClient; - private final SearchAsyncClient searchAsyncClient; - private final String collectionName; - private final AzureAISearchVectorStoreRecordCollectionOptions options; - private final VectorStoreRecordDefinition recordDefinition; - - // List of non-vector fields. Used to fetch only non-vector fields when vectors are not requested - private final List nonVectorFields = new ArrayList<>(); - private final String firstVectorFieldName; - - /** - * Creates a new instance of {@link AzureAISearchVectorStoreRecordCollection}. - * - * @param searchIndexAsyncClient The Azure AI Search client. - * @param collectionName The name of the collection. - * @param options The options for the collection. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public AzureAISearchVectorStoreRecordCollection( - @Nonnull SearchIndexAsyncClient searchIndexAsyncClient, - @Nonnull String collectionName, - @Nonnull AzureAISearchVectorStoreRecordCollectionOptions options) { - this.searchIndexAsyncClient = searchIndexAsyncClient; - this.collectionName = collectionName; - this.searchAsyncClient = searchIndexAsyncClient.getSearchAsyncClient(collectionName); - this.options = options; - - // If record definition is not provided, create one from the record class - this.recordDefinition = options.getRecordDefinition() == null - ? VectorStoreRecordDefinition.fromRecordClass(options.getRecordClass()) - : options.getRecordDefinition(); - - // Validate supported types - VectorStoreRecordDefinition.validateSupportedTypes( - Collections.singletonList(recordDefinition.getKeyField()), - supportedKeyTypes); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getDataFields()), - supportedDataTypes); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getVectorFields()), - supportedVectorTypes); - - // Add non-vector fields to the list - nonVectorFields.add(this.recordDefinition.getKeyField().getEffectiveStorageName()); - nonVectorFields.addAll(this.recordDefinition.getDataFields().stream() - .map(VectorStoreRecordDataField::getEffectiveStorageName) - .collect(Collectors.toList())); - - firstVectorFieldName = recordDefinition.getVectorFields().isEmpty() ? null - : recordDefinition.getVectorFields().get(0).getName(); - } - - @Override - public String getCollectionName() { - return collectionName; - } - - private Mono> getIndexesAsync() { - return searchIndexAsyncClient.listIndexes().map(SearchIndex::getName) - .collect(Collectors.toList()); - } - - @Override - public Mono collectionExistsAsync() { - return getIndexesAsync() - .map(list -> list.stream().anyMatch(name -> name.equalsIgnoreCase(collectionName))); - } - - @Override - public Mono> createCollectionAsync() { - List searchFields = new ArrayList<>(); - List algorithms = new ArrayList<>(); - List profiles = new ArrayList<>(); - - for (VectorStoreRecordField field : this.recordDefinition.getAllFields()) { - if (field instanceof VectorStoreRecordKeyField) { - searchFields.add(AzureAISearchVectorStoreCollectionCreateMapping - .mapKeyField((VectorStoreRecordKeyField) field)); - } else if (field instanceof VectorStoreRecordDataField) { - searchFields.add(AzureAISearchVectorStoreCollectionCreateMapping - .mapDataField((VectorStoreRecordDataField) field)); - } else { - searchFields.add(AzureAISearchVectorStoreCollectionCreateMapping - .mapVectorField((VectorStoreRecordVectorField) field)); - AzureAISearchVectorStoreCollectionCreateMapping - .updateVectorSearchParameters(algorithms, profiles, - (VectorStoreRecordVectorField) field); - } - } - - SearchIndex newIndex = new SearchIndex(collectionName) - .setFields(searchFields) - .setVectorSearch(new com.azure.search.documents.indexes.models.VectorSearch() - .setAlgorithms(algorithms) - .setProfiles(profiles)); - - return searchIndexAsyncClient.createIndex(newIndex).then(Mono.just(this)); - } - - @Override - public Mono> createCollectionIfNotExistsAsync() { - return collectionExistsAsync().flatMap( - exists -> { - if (!exists) { - return createCollectionAsync(); - } - return Mono.empty(); - }) - .then(Mono.just(this)); - } - - @Override - public Mono deleteCollectionAsync() { - return searchIndexAsyncClient.deleteIndex(this.collectionName).then(); - } - - @Override - public Mono getAsync( - @Nonnull String key, GetRecordOptions options) { - // If vectors are not requested, only fetch non-vector fields - List selectedFields = null; - if (options == null || !options.isIncludeVectors()) { - selectedFields = Collections.unmodifiableList(nonVectorFields); - } - - VectorStoreRecordMapper mapper = this.options - .getVectorStoreRecordMapper(); - - // Use custom mapper if available - if (mapper != null && mapper.getStorageModelToRecordMapper() != null) { - return searchAsyncClient.getDocument(key, SearchDocument.class) - .map(record -> mapper.mapStorageModelToRecord(record, options)); - } - - return searchAsyncClient - .getDocumentWithResponse(key, this.options.getRecordClass(), selectedFields) - .flatMap(response -> { - int statusCode = response.getStatusCode(); - if (statusCode >= 200 && statusCode < 300) { - return Mono.just(response.getValue()); - } - if (response.getStatusCode() == 404) { - return Mono.error(new SKException("Record not found: " + key)); - } - return Mono.error(new SKException("Failed to get record: " + key + ". Status code: " - + statusCode)); - }); - - } - - @Override - public Mono> getBatchAsync( - @Nonnull List keys, - GetRecordOptions options) { - return Flux.fromIterable(keys) - .flatMap(key -> getAsync(key, options).flux()) - .collect(Collectors.toList()); - } - - @Override - public Mono upsertAsync(@Nonnull Record record, UpsertRecordOptions options) { - return upsertBatchAsync(Collections.singletonList(record), options) - .map(Collection::iterator) - .map(Iterator::next); - } - - @Override - public Mono> upsertBatchAsync( - @Nonnull List records, UpsertRecordOptions options) { - if (records.isEmpty()) { - return Mono.just(Collections.emptyList()); - } - - VectorStoreRecordMapper mapper = this.options - .getVectorStoreRecordMapper(); - Iterable documents; - - // Use custom mapper if available - if (mapper != null && mapper.getRecordToStorageModelMapper() != null) { - documents = records.stream() - .map(this.options.getVectorStoreRecordMapper()::mapRecordToStorageModel) - .collect(Collectors.toList()); - } else { - documents = records; - } - - return searchAsyncClient.uploadDocuments(documents) - .map(IndexDocumentsResult::getResults) - .map( - results -> results.stream() - .map(IndexingResult::getKey) - .collect(Collectors.toList())); - } - - @Override - public Mono deleteAsync(String key, DeleteRecordOptions options) { - return deleteBatchAsync(Collections.singletonList(key), options); - } - - @Override - public Mono deleteBatchAsync(List keys, DeleteRecordOptions options) { - return searchAsyncClient.deleteDocuments(keys.stream().map(key -> { - SearchDocument document = new SearchDocument(); - document.put(this.recordDefinition.getKeyField().getEffectiveStorageName(), key); - return document; - }).collect(Collectors.toList())).then(); - } - - private SearchOptions configureVectorSearchOptions( - List vectorQueries, VectorSearchOptions options) { - String filter = AzureAISearchVectorStoreCollectionSearchMapping.getInstance() - .getFilter(options.getVectorSearchFilter(), recordDefinition); - - SearchOptions searchOptions = new SearchOptions() - .setFilter(filter) - .setTop(options.getTop()) - .setSkip(options.getSkip()) - .setVectorSearchOptions(new com.azure.search.documents.models.VectorSearchOptions() - .setQueries(vectorQueries)); - - if (!options.isIncludeVectors()) { - searchOptions.setSelect(nonVectorFields.toArray(new String[0])); - } - - return searchOptions; - } - - private Mono> searchAndMapAsync(String query, - SearchOptions searchOptions, - boolean includeVectors) { - VectorStoreRecordMapper mapper = this.options - .getVectorStoreRecordMapper(); - - return this.searchAsyncClient.search(query, searchOptions) - .flatMap(response -> { - Record record; - - // Use custom mapper if available - if (mapper != null && mapper.getStorageModelToRecordMapper() != null) { - record = mapper - .mapStorageModelToRecord(response.getDocument(SearchDocument.class), - new GetRecordOptions(includeVectors)); - } else { - record = response.getDocument(this.options.getRecordClass()); - } - - return Mono.just(new VectorSearchResult<>(record, response.getScore())); - }).collectList().flatMap(results -> Mono.just( - new VectorSearchResults<>(results))); - } - - /** - * Vectorizable text search. This method searches for records that are similar to the given text after vectorization. - *

- * Vectorizer configuration must be set up in the Azure AI Search index. - * - * @param searchText The text to search with. - * @param options The options to use for the search. - * @return A list of search results. - */ - @Override - public Mono> searchAsync(String searchText, - VectorSearchOptions options) { - if (firstVectorFieldName == null) { - throw new SKException("No vector fields defined. Cannot perform vector search"); - } - - if (options == null) { - options = VectorSearchOptions.createDefault(firstVectorFieldName); - } - - List vectorQueries = new ArrayList<>(); - vectorQueries.add(new VectorizableTextQuery(searchText) - .setFields(recordDefinition.getField(options.getVectorFieldName() != null - ? options.getVectorFieldName() - : firstVectorFieldName).getEffectiveStorageName()) - .setKNearestNeighborsCount(options.getTop())); - - return searchAndMapAsync(null, - configureVectorSearchOptions(vectorQueries, options), - options.isIncludeVectors()); - } - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param options The options to use for the search. - * @return A list of search results. - */ - @Override - public Mono> searchAsync(List vector, - VectorSearchOptions options) { - return hybridSearchAsync(null, vector, options, null); - } - - /** - * Hybrid search. This method searches for records that are similar to the given text and vector. - * - * @param searchText The text to search with. - * If null, only vector search is performed. - * @param vector The vector to search with. - * If null, only full text search is performed. - * @param options The vector search options used for the search. - * @param additionalSearchOptions AzureAI search additional options. - * If Filter, Top, Skip, Select or VectorSearchOptions are not null, they will be used instead of the default options. - *

- * If null, default search options are used. - */ - public Mono> hybridSearchAsync(String searchText, - List vector, VectorSearchOptions options, SearchOptions additionalSearchOptions) { - SearchOptions searchOptions = new SearchOptions(); - - if (vector != null) { - if (firstVectorFieldName == null) { - throw new SKException("No vector fields defined. Cannot perform vector search"); - } - - if (options == null) { - options = VectorSearchOptions.createDefault(firstVectorFieldName); - } - - List vectorQueries = new ArrayList<>(); - vectorQueries.add(new VectorizedQuery(vector) - .setFields(recordDefinition.getField(options.getVectorFieldName() != null - ? options.getVectorFieldName() - : firstVectorFieldName).getEffectiveStorageName()) - .setKNearestNeighborsCount(options.getTop())); - - // Configure default vector search options - searchOptions = configureVectorSearchOptions(vectorQueries, options); - } - - // Configure additional search options - if (additionalSearchOptions != null) { - searchOptions - .setQueryType(additionalSearchOptions.getQueryType()) - .setSemanticSearchOptions(additionalSearchOptions.getSemanticSearchOptions()) - .setFacets(additionalSearchOptions.getFacets() != null - ? additionalSearchOptions.getFacets().toArray(new String[0]) - : null) - .setHighlightFields(additionalSearchOptions.getHighlightFields() != null - ? additionalSearchOptions.getHighlightFields().toArray(new String[0]) - : null) - .setHighlightPreTag(additionalSearchOptions.getHighlightPreTag()) - .setHighlightPostTag(additionalSearchOptions.getHighlightPostTag()) - .setMinimumCoverage(additionalSearchOptions.getMinimumCoverage()) - .setOrderBy(additionalSearchOptions.getOrderBy() != null - ? additionalSearchOptions.getOrderBy().toArray(new String[0]) - : null) - .setScoringParameters(additionalSearchOptions.getScoringParameters() != null - ? additionalSearchOptions.getScoringParameters().stream() - .map(s -> new ScoringParameter(s.getName(), s.getValues())) - .toArray(ScoringParameter[]::new) - : null) - .setScoringProfile(additionalSearchOptions.getScoringProfile()) - .setSearchFields(additionalSearchOptions.getSearchFields() != null - ? additionalSearchOptions.getSearchFields().toArray(new String[0]) - : null) - .setIncludeTotalCount(additionalSearchOptions.isTotalCountIncluded()) - .setSearchMode(additionalSearchOptions.getSearchMode()) - .setScoringStatistics(additionalSearchOptions.getScoringStatistics()) - .setSessionId(additionalSearchOptions.getSessionId()); - - // Override default vector options if provided - if (additionalSearchOptions.getFilter() != null) { - searchOptions.setFilter(additionalSearchOptions.getFilter()); - } - if (additionalSearchOptions.getTop() != null) { - searchOptions.setTop(additionalSearchOptions.getTop()); - } - if (additionalSearchOptions.getSkip() != null) { - searchOptions.setSkip(additionalSearchOptions.getSkip()); - } - if (additionalSearchOptions.getVectorSearchOptions() != null) { - searchOptions - .setVectorSearchOptions(additionalSearchOptions.getVectorSearchOptions()); - } - if (additionalSearchOptions.getSelect() != null) { - searchOptions.setSelect(additionalSearchOptions.getSelect().toArray(new String[0])); - } - } - - return searchAndMapAsync(searchText, searchOptions, - options != null && options.isIncludeVectors()); - } -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionFactory.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionFactory.java deleted file mode 100644 index ada0f70be..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.azure.search.documents.indexes.SearchIndexAsyncClient; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; - -/** - * Factory for creating Azure AI Search vector store record collections. - */ -public interface AzureAISearchVectorStoreRecordCollectionFactory { - - /** - * Creates a new Azure AI Search vector store record collection. - * - * @param client The Azure AI Search client. - * @param collectionName The name of the collection. - * @param recordClass The class type of the record. - * @param recordDefinition The record definition. - * @param The record type. - * @return The new Azure AI Search vector store record collection. - */ - AzureAISearchVectorStoreRecordCollection createVectorStoreRecordCollection( - SearchIndexAsyncClient client, - String collectionName, - Class recordClass, - VectorStoreRecordDefinition recordDefinition); -} diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionOptions.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionOptions.java deleted file mode 100644 index 2cd143607..000000000 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.azureaisearch; - -import com.azure.search.documents.SearchDocument; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Options for an Azure AI Search vector store. - * - * @param the record type - */ -public class AzureAISearchVectorStoreRecordCollectionOptions - implements VectorStoreRecordCollectionOptions { - private final Class recordClass; - @Nullable - private final VectorStoreRecordMapper vectorStoreRecordMapper; - @Nullable - private final VectorStoreRecordDefinition recordDefinition; - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Gets the key class. - * - * @return the key class - */ - @Override - public Class getKeyClass() { - return String.class; - } - - /** - * Gets the record class. - * - * @return the record class - */ - public Class getRecordClass() { - return recordClass; - } - - /** - * Gets the record definition. - * - * @return the record definition - */ - @Nullable - public VectorStoreRecordDefinition getRecordDefinition() { - return recordDefinition; - } - - /** - * Gets the vector store record mapper. - * - * @return the vector store record mapper - */ - @Nullable - public VectorStoreRecordMapper getVectorStoreRecordMapper() { - return vectorStoreRecordMapper; - } - - private AzureAISearchVectorStoreRecordCollectionOptions( - @Nonnull Class recordClass, - @Nullable VectorStoreRecordMapper vectorStoreRecordMapper, - @Nullable VectorStoreRecordDefinition recordDefinition) { - this.recordClass = recordClass; - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - this.recordDefinition = recordDefinition; - } - - /** - * Builder for {@link AzureAISearchVectorStoreRecordCollectionOptions}. - * - * @param the record type - */ - public static class Builder { - - @Nullable - private VectorStoreRecordMapper vectorStoreRecordMapper; - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - - /** - * Sets the record class. - * @param recordClass the record Class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record mapper. - * - * @param vectorStoreRecordMapper the vector store record mapper - * @return the builder - */ - public Builder withVectorStoreRecordMapper( - VectorStoreRecordMapper vectorStoreRecordMapper) { - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - return this; - } - - /** - * Sets the record definition. - * - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Builds the options. - * - * @return the options - */ - public AzureAISearchVectorStoreRecordCollectionOptions build() { - if (recordClass == null) { - throw new SKException("recordClass must be provided"); - } - - return new AzureAISearchVectorStoreRecordCollectionOptions<>( - recordClass, - vectorStoreRecordMapper, - recordDefinition); - } - } -} diff --git a/data/semantickernel-data-hsqldb/pom.xml b/data/semantickernel-data-hsqldb/pom.xml deleted file mode 100644 index 1cd331795..000000000 --- a/data/semantickernel-data-hsqldb/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-data-hsqldb - Semantic Kernel HLSQLDB connector - Provides a HLSQLDB connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.spotbugs - spotbugs-annotations - - - \ No newline at end of file diff --git a/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java b/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java deleted file mode 100644 index 484313168..000000000 --- a/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.hsqldb; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.time.OffsetDateTime; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.sql.DataSource; - -/** - * The HSQLDB vector store query provider. - * Provides the necessary methods to interact with a HSQLDB vector store and vector store collections. - */ -public class HSQLDBVectorStoreQueryProvider extends JDBCVectorStoreQueryProvider { - - private final ObjectMapper objectMapper; - - @SuppressFBWarnings("EI_EXPOSE_REP2") - private HSQLDBVectorStoreQueryProvider( - DataSource dataSource, - String collectionsTable, - String prefixForCollectionTables, - int defaultVarCharLength, - ObjectMapper objectMapper) { - super( - dataSource, - collectionsTable, - prefixForCollectionTables, - buildSupportedKeyTypes(defaultVarCharLength), - buildSupportedDataTypes(defaultVarCharLength), - buildSupportedVectorTypes(defaultVarCharLength)); - this.objectMapper = objectMapper; - } - - private static Map, String> buildSupportedVectorTypes(int defaultVarCharLength) { - HashMap, String> supportedVectorTypes = new HashMap<>(); - supportedVectorTypes.put(String.class, "VARCHAR(" + defaultVarCharLength + ")"); - supportedVectorTypes.put(List.class, "VARCHAR(" + defaultVarCharLength + ")"); - supportedVectorTypes.put(Collection.class, "VARCHAR(" + defaultVarCharLength + ")"); - return supportedVectorTypes; - } - - private static Map, String> buildSupportedDataTypes(int defaultVarCharLength) { - HashMap, String> supportedDataTypes = new HashMap<>(); - supportedDataTypes.put(String.class, "VARCHAR(" + defaultVarCharLength + ")"); - supportedDataTypes.put(Integer.class, "INTEGER"); - supportedDataTypes.put(int.class, "INTEGER"); - supportedDataTypes.put(Long.class, "BIGINT"); - supportedDataTypes.put(long.class, "BIGINT"); - supportedDataTypes.put(Float.class, "REAL"); - supportedDataTypes.put(float.class, "REAL"); - supportedDataTypes.put(Double.class, "DOUBLE"); - supportedDataTypes.put(double.class, "DOUBLE"); - supportedDataTypes.put(Boolean.class, "BOOLEAN"); - supportedDataTypes.put(boolean.class, "BOOLEAN"); - supportedDataTypes.put(OffsetDateTime.class, "TIMESTAMPTZ"); - supportedDataTypes.put(List.class, "TEXT"); - return supportedDataTypes; - } - - private static HashMap, String> buildSupportedKeyTypes(int defaultVarCharLength) { - HashMap, String> supportedKeyTypes = new HashMap<>(); - supportedKeyTypes.put(String.class, "VARCHAR(" + defaultVarCharLength + ")"); - return supportedKeyTypes; - } - - private void setUpsertStatementValues(PreparedStatement statement, Object record, - List fields) { - JsonNode jsonNode = objectMapper.valueToTree(record); - - for (int i = 0; i < fields.size(); ++i) { - VectorStoreRecordField field = fields.get(i); - try { - JsonNode valueNode = jsonNode.get(field.getEffectiveStorageName()); - - if (field instanceof VectorStoreRecordVectorField) { - // Convert the vector field to a string - if (!field.getFieldType().equals(String.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } else if (field instanceof VectorStoreRecordDataField) { - // Convert List field to a string - if (field.getFieldType().equals(List.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } - - statement.setObject(i + 1, - objectMapper.convertValue(valueNode, field.getFieldType())); - } catch (SQLException | JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - /** - * Upserts records into the collection. - * - * @param collectionName the collection name - * @param records the records to upsert - * @param recordDefinition the record definition - * @param options the upsert options - * @throws SKException if the upsert fails - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - // SQL query is generated dynamically with valid identifiers - public void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition recordDefinition, UpsertRecordOptions options) { - validateSQLidentifier(getCollectionTableName(collectionName)); - - List fields = recordDefinition.getAllFields(); - - String keyName = recordDefinition.getKeyField().getStorageName(); - - String updater = fields - .stream() - .map(VectorStoreRecordField::getStorageName) - .map(it -> "t." + it + "=vals." + it) - .collect(Collectors.joining(",")); - - String setter = fields - .stream() - .map(VectorStoreRecordField::getStorageName) - .map(it -> "vals." + it) - .collect(Collectors.joining(",")); - - String query = formatQuery( - "MERGE INTO %s AS t USING (VALUES (%s)) AS vals(%s) " - + "ON t.%s=vals.%s WHEN MATCHED THEN UPDATE SET %s " - + "WHEN NOT MATCHED THEN INSERT VALUES %s", - getCollectionTableName(collectionName), - getWildcardString(fields.size()), - getQueryColumnsFromFields(fields), - keyName, - keyName, - updater, - setter); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (Object record : records) { - setUpsertStatementValues(statement, record, recordDefinition.getAllFields()); - statement.addBatch(); - } - - statement.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to upsert records", e); - } - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * The builder for the HSQLDB vector store query provider. - */ - public static class Builder - extends JDBCVectorStoreQueryProvider.Builder { - - private DataSource dataSource; - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - private int defaultVarCharLength = 255; - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the data source. - * - * @param dataSource the data source - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * - * @param collectionsTable the collections table name - * @return the builder - */ - public Builder withCollectionsTable(String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Sets the default VARCHAR length. - * - * @param defaultVarCharLength the default VARCHAR length - * @return the builder - */ - public Builder setDefaultVarCharLength(int defaultVarCharLength) { - this.defaultVarCharLength = defaultVarCharLength; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the HSQLDB vector store query provider. - * - * @return the HSQLDB vector store query provider - */ - public HSQLDBVectorStoreQueryProvider build() { - if (dataSource == null) { - throw new SKException("DataSource is required"); - } - - return new HSQLDBVectorStoreQueryProvider( - dataSource, - collectionsTable, - prefixForCollectionTables, - defaultVarCharLength, - objectMapper); - } - - } -} diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml deleted file mode 100644 index 077d4da6c..000000000 --- a/data/semantickernel-data-jdbc/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-data-jdbc - Semantic Kernel JDBC connector - Provides a JDBC connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api-data - provided - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - provided - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - - - org.slf4j - slf4j-api - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.jknack - handlebars - - - com.google.code.findbugs - jsr305 - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.apache.commons - commons-text - - - org.postgresql - postgresql - 42.7.7 - - - org.xerial - sqlite-jdbc - 3.47.0.0 - - - com.oracle.database.jdbc - ojdbc11 - 23.7.0.25.01 - - - \ No newline at end of file diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStore.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStore.java deleted file mode 100644 index ddc2f7501..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStore.java +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.sql.DataSource; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -/** - * A JDBC vector store. - */ -public class JDBCVectorStore implements SQLVectorStore { - - private final DataSource dataSource; - private final JDBCVectorStoreOptions options; - private final SQLVectorStoreQueryProvider queryProvider; - - /** - * Creates a new instance of the {@link JDBCVectorStore}. If using this constructor, call - * {@link #prepareAsync()} before using the vector store. - * - * @param dataSource the connection - * @param options the options - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed - public JDBCVectorStore(@Nonnull DataSource dataSource, - @Nullable JDBCVectorStoreOptions options) { - this.dataSource = dataSource; - this.options = options; - - if (this.options != null && this.options.getQueryProvider() != null) { - this.queryProvider = this.options.getQueryProvider(); - } else { - this.queryProvider = JDBCVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - } - } - - /** - * Creates a new builder for the vector store. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Gets a collection from the vector store. - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - * @return The collection. - */ - @Override - public VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull VectorStoreRecordCollectionOptions options) { - if (!options.getKeyClass().equals(String.class)) { - throw new SKException("JDBC only supports string keys"); - } - if (options.getRecordClass() == null) { - throw new SKException("Record class is required"); - } - - if (this.options != null && this.options.getVectorStoreRecordCollectionFactory() != null) { - return (VectorStoreRecordCollection) this.options - .getVectorStoreRecordCollectionFactory() - .createVectorStoreRecordCollection( - dataSource, - collectionName, - options.getRecordClass(), - options.getRecordDefinition()); - } - - JDBCVectorStoreRecordCollectionOptions jdbcOptions = (JDBCVectorStoreRecordCollectionOptions) options; - return (VectorStoreRecordCollection) new JDBCVectorStoreRecordCollection<>( - dataSource, - collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withCollectionsTableName(jdbcOptions.getCollectionsTableName()) - .withPrefixForCollectionTables(jdbcOptions.getPrefixForCollectionTables()) - .withQueryProvider(jdbcOptions.getQueryProvider() == null ? queryProvider - : jdbcOptions.getQueryProvider()) - .withRecordClass(jdbcOptions.getRecordClass()) - .withRecordDefinition(jdbcOptions.getRecordDefinition()) - .withVectorStoreRecordMapper(jdbcOptions.getVectorStoreRecordMapper()) - .build()); - } - - /** - * Gets a collection from the vector store. - * - * @param collectionName The name of the collection. - * @param recordClass The class type of the record. - * @param recordDefinition The record definition. - * @param The record type. - * @return The collection. - */ - public VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull Class recordClass, - @Nullable VectorStoreRecordDefinition recordDefinition) { - return getCollection( - collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(recordClass) - .withRecordDefinition(recordDefinition) - .withQueryProvider(this.queryProvider) - .build()); - } - - /** - * Gets the names of all collections in the vector store. - * - * @return A list of collection names. - */ - @Override - public Mono> getCollectionNamesAsync() { - return Mono.fromCallable(queryProvider::getCollectionNames) - .subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Prepares the vector store. - */ - @Override - public Mono prepareAsync() { - return Mono.fromRunnable(queryProvider::prepareVectorStore) - .subscribeOn(Schedulers.boundedElastic()).then(); - } - - /** - * Builder for creating a {@link JDBCVectorStore}. - */ - public static class Builder { - - private DataSource dataSource; - private JDBCVectorStoreOptions options; - - /** - * Sets the data source. - * - * @param dataSource the data source - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the options. - * - * @param options the options - * @return the builder - */ - public Builder withOptions(JDBCVectorStoreOptions options) { - this.options = options; - return this; - } - - /** - * Builds the {@link JDBCVectorStore}. - * - * @return the {@link JDBCVectorStore} - */ - public JDBCVectorStore build() { - return buildAsync().block(); - } - - /** - * Builds the {@link JDBCVectorStore} asynchronously. - * - * @return the {@link Mono} with the {@link JDBCVectorStore} - */ - public Mono buildAsync() { - if (dataSource == null) { - throw new SKException("dataSource is required"); - } - - JDBCVectorStore vectorStore = new JDBCVectorStore(dataSource, options); - return vectorStore.prepareAsync().thenReturn(vectorStore); - } - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreOptions.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreOptions.java deleted file mode 100644 index 729ebbbdc..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreOptions.java +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nullable; - -/** - * Options for the JDBC vector store. - */ -public class JDBCVectorStoreOptions { - @Nullable - private final JDBCVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - @Nullable - private final SQLVectorStoreQueryProvider queryProvider; - - /** - * Creates a new instance of the JDBC vector store options. - * - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - * @param queryProvider The query provider. - * - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource in queryProvider is not exposed - public JDBCVectorStoreOptions( - @Nullable SQLVectorStoreQueryProvider queryProvider, - @Nullable JDBCVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.queryProvider = queryProvider; - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - } - - /** - * Creates a new instance of the JDBC vector store options. - */ - public JDBCVectorStoreOptions() { - this(null, null); - } - - /** - * Gets the query provider. - * - * @return the query provider - */ - @Nullable - @SuppressFBWarnings("EI_EXPOSE_REP") // DataSource in queryProvider is not exposed - public SQLVectorStoreQueryProvider getQueryProvider() { - return queryProvider; - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Gets the vector store record collection factory. - * - * @return the vector store record collection factory - */ - @Nullable - public JDBCVectorStoreRecordCollectionFactory getVectorStoreRecordCollectionFactory() { - return vectorStoreRecordCollectionFactory; - } - - /** - * Builder for JDBC vector store options. - */ - public static class Builder { - @Nullable - private SQLVectorStoreQueryProvider queryProvider; - @Nullable - private JDBCVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - - /** - * Sets the query provider. - * - * @param queryProvider The query provider. - * @return The updated builder instance. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource in queryProvider is not exposed - public Builder withQueryProvider(SQLVectorStoreQueryProvider queryProvider) { - this.queryProvider = queryProvider; - return this; - } - - /** - * Sets the vector store record collection factory. - * - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - * @return The updated builder instance. - */ - public Builder withVectorStoreRecordCollectionFactory( - JDBCVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - return this; - } - - /** - * Builds the JDBC vector store options. - * - * @return The JDBC vector store options. - */ - public JDBCVectorStoreOptions build() { - return new JDBCVectorStoreOptions(queryProvider, vectorStoreRecordCollectionFactory); - } - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java deleted file mode 100644 index 2fcc2d5b7..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java +++ /dev/null @@ -1,769 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.vectorsearch.VectorOperations; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.GuardedBy; -import javax.sql.DataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A JDBC vector store query provider. - */ -public class JDBCVectorStoreQueryProvider - implements SQLVectorStoreQueryProvider, - SQLVectorStoreFilterQueryProvider { - - private static final Logger LOGGER = LoggerFactory - .getLogger(JDBCVectorStoreQueryProvider.class); - - protected final Map, String> supportedKeyTypes; - protected final Map, String> supportedDataTypes; - protected final Map, String> supportedVectorTypes; - - protected final DataSource dataSource; - private final String collectionsTable; - private final String prefixForCollectionTables; - - private final Object dbCreationLock = new Object(); - - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed - protected JDBCVectorStoreQueryProvider( - @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables) { - this.dataSource = dataSource; - this.collectionsTable = collectionsTable; - this.prefixForCollectionTables = prefixForCollectionTables; - - supportedKeyTypes = new HashMap<>(); - supportedKeyTypes.put(String.class, "VARCHAR(255)"); - - supportedDataTypes = new HashMap<>(); - supportedDataTypes.put(String.class, "TEXT"); - supportedDataTypes.put(Integer.class, "INTEGER"); - supportedDataTypes.put(int.class, "INTEGER"); - supportedDataTypes.put(Long.class, "BIGINT"); - supportedDataTypes.put(long.class, "BIGINT"); - supportedDataTypes.put(Float.class, "REAL"); - supportedDataTypes.put(float.class, "REAL"); - supportedDataTypes.put(Double.class, "DOUBLE"); - supportedDataTypes.put(double.class, "DOUBLE"); - supportedDataTypes.put(Boolean.class, "BOOLEAN"); - supportedDataTypes.put(boolean.class, "BOOLEAN"); - supportedDataTypes.put(OffsetDateTime.class, "TIMESTAMPTZ"); - supportedDataTypes.put(List.class, "TEXT"); - - supportedVectorTypes = new HashMap<>(); - supportedVectorTypes.put(String.class, "TEXT"); - supportedVectorTypes.put(List.class, "TEXT"); - supportedVectorTypes.put(Collection.class, "TEXT"); - } - - /** - * Creates a new instance of the JDBCVectorStoreQueryProvider class. - * - * @param dataSource the data source - * @param collectionsTable the collections table - * @param prefixForCollectionTables the prefix for collection tables - * @param supportedKeyTypes the supported key types - * @param supportedDataTypes the supported data types - * @param supportedVectorTypes the supported vector types - */ - public JDBCVectorStoreQueryProvider( - @SuppressFBWarnings("EI_EXPOSE_REP2") @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables, - @Nonnull Map, String> supportedKeyTypes, - @Nonnull Map, String> supportedDataTypes, - @Nonnull Map, String> supportedVectorTypes) { - this.dataSource = dataSource; - this.collectionsTable = collectionsTable; - this.prefixForCollectionTables = prefixForCollectionTables; - this.supportedKeyTypes = new HashMap<>(supportedKeyTypes); - this.supportedDataTypes = new HashMap<>(supportedDataTypes); - this.supportedVectorTypes = new HashMap<>(supportedVectorTypes); - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Formats a wildcard string for a query. - * - * @param wildcards the number of wildcards - * @return the formatted wildcard string - */ - protected String getWildcardString(int wildcards) { - return Stream.generate(() -> "?") - .limit(wildcards) - .collect(Collectors.joining(", ")); - } - - /** - * Gets the key column name from a key field. - * - * @param keyField the key field - * @return the key column name - */ - protected String getKeyColumnName(VectorStoreRecordField keyField) { - return validateSQLidentifier(keyField.getEffectiveStorageName()); - } - - /** - * Formats the query columns from a record definition. - * - * @param fields the fields to get the columns from - * @return the formatted query columns - */ - protected String getQueryColumnsFromFields(List fields) { - return fields.stream() - .map(VectorStoreRecordField::getEffectiveStorageName) - .map(JDBCVectorStoreQueryProvider::validateSQLidentifier) - .collect(Collectors.joining(", ")); - } - - /** - * Formats the column names and types for a table. - * - * @param fields the fields - * @param types the types - * @return the formatted column names and types - */ - protected String getColumnNamesAndTypes(List fields, - Map, String> types) { - List columns = fields.stream() - .map(field -> validateSQLidentifier(field.getEffectiveStorageName()) + " " - + types.get(field.getFieldType())) - .collect(Collectors.toList()); - - return String.join(", ", columns); - } - - protected String getCollectionTableName(String collectionName) { - return validateSQLidentifier(prefixForCollectionTables + collectionName); - } - - /** - * Gets the supported key types and their corresponding SQL types. - * - * @return the supported key types - */ - @Override - public Map, String> getSupportedKeyTypes() { - return new HashMap<>(this.supportedKeyTypes); - } - - /** - * Gets the supported data types and their corresponding SQL types. - * - * @return the supported data types - */ - @Override - public Map, String> getSupportedDataTypes() { - return new HashMap<>(this.supportedDataTypes); - } - - /** - * Gets the supported vector types and their corresponding SQL types. - * - * @return the supported vector types - */ - @Override - public Map, String> getSupportedVectorTypes() { - return new HashMap<>(this.supportedVectorTypes); - } - - /** - * Prepares the vector store. Executes any necessary setup steps for the vector store. - * - * @throws SKException if an error occurs while preparing the vector store - */ - @Override - public void prepareVectorStore() { - String createCollectionsTable = formatQuery( - "CREATE TABLE IF NOT EXISTS %s (collectionId VARCHAR(255) PRIMARY KEY)", - validateSQLidentifier(collectionsTable)); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement createTable = connection.prepareStatement(createCollectionsTable)) { - createTable.execute(); - } catch (SQLException e) { - throw new SKException("Failed to prepare vector store", e); - } - } - - /** - * Checks if the types of the record class fields are supported. - * - * @param recordDefinition the record definition - * @throws SKException if the types are not supported - */ - @Override - public void validateSupportedTypes(VectorStoreRecordDefinition recordDefinition) { - - VectorStoreRecordDefinition.validateSupportedTypes( - Collections.singletonList(recordDefinition.getKeyField()), - getSupportedKeyTypes().keySet()); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getDataFields()), - getSupportedDataTypes().keySet()); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getVectorFields()), - getSupportedVectorTypes().keySet()); - } - - /** - * Checks if a collection exists. - * - * @param collectionName the collection name - * @return true if the collection exists, false otherwise - * @throws SKException if an error occurs while checking if the collection exists - */ - @Override - public boolean collectionExists(String collectionName) { - String query = formatQuery("SELECT 1 FROM %s WHERE collectionId = ?", - validateSQLidentifier(collectionsTable)); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - statement.setObject(1, collectionName); - - return statement.executeQuery().next(); - } catch (SQLException e) { - throw new SKException("Failed to check if collection exists", e); - } - } - - /** - * Creates a collection. - * - * @param collectionName the collection name - * @param recordDefinition the record definition - * @throws SKException if an error occurs while creating the collection - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - @GuardedBy("dbCreationLock") - // SQL query is generated dynamically with valid identifiers - public void createCollection(String collectionName, - VectorStoreRecordDefinition recordDefinition) { - - synchronized (dbCreationLock) { - // No approximate search is supported in JDBCVectorStoreQueryProvider - if (recordDefinition.getVectorFields().stream() - .anyMatch( - field -> field.getIndexKind() != null && field.getIndexKind() != IndexKind.FLAT - && field.getIndexKind() != IndexKind.UNDEFINED)) { - LOGGER - .warn(String.format( - "Indexes are not supported in %s. Ignoring indexKind property.", - this.getClass().getName())); - } - - String createStorageTable = formatQuery("CREATE TABLE IF NOT EXISTS %s (" - + "%s VARCHAR(255) PRIMARY KEY, " - + "%s, " - + "%s);", - getCollectionTableName(collectionName), - getKeyColumnName(recordDefinition.getKeyField()), - getColumnNamesAndTypes(new ArrayList<>(recordDefinition.getDataFields()), - getSupportedDataTypes()), - getColumnNamesAndTypes(new ArrayList<>(recordDefinition.getVectorFields()), - getSupportedVectorTypes())); - - String insertCollectionQuery = this.getInsertCollectionQuery(collectionsTable); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement createTable = connection.prepareStatement(createStorageTable)) { - createTable.execute(); - } catch (SQLException e) { - throw new SKException("Failed to create collection", e); - } - - try (Connection connection = dataSource.getConnection(); - PreparedStatement insert = connection.prepareStatement(insertCollectionQuery)) { - insert.setObject(1, collectionName); - insert.execute(); - } catch (SQLException e) { - throw new SKException("Failed to insert collection", e); - } - } - } - - protected String getInsertCollectionQuery(String collectionsTable) { - return formatQuery( - "INSERT IGNORE INTO %s (collectionId) VALUES (?)", - validateSQLidentifier(collectionsTable)); - } - - /** - * Deletes a collection. - * - * @param collectionName the collection name - * @throws SKException if an error occurs while deleting the collection - */ - @Override - @GuardedBy("dbCreationLock") - public void deleteCollection(String collectionName) { - synchronized (dbCreationLock) { - String deleteCollectionOperation = formatQuery("DELETE FROM %s WHERE collectionId = ?", - validateSQLidentifier(collectionsTable)); - String dropTableOperation = formatQuery("DROP TABLE %s", - getCollectionTableName(collectionName)); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement deleteCollection = connection - .prepareStatement(deleteCollectionOperation)) { - deleteCollection.setObject(1, collectionName); - deleteCollection.execute(); - } catch (SQLException e) { - throw new SKException("Failed to delete collection", e); - } - - try (Connection connection = dataSource.getConnection(); - PreparedStatement dropTable = connection.prepareStatement(dropTableOperation)) { - dropTable.execute(); - } catch (SQLException e) { - throw new SKException("Failed to drop table", e); - } - } - } - - /** - * Gets the collection names. - * - * @return the collection names - * @throws SKException if an error occurs while getting the collection names - */ - @Override - public List getCollectionNames() { - String query = formatQuery("SELECT collectionId FROM %s", - validateSQLidentifier(collectionsTable)); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - List collectionNames = new ArrayList<>(); - ResultSet resultSet = statement.executeQuery(); - - while (resultSet.next()) { - collectionNames.add(resultSet.getString(1)); - } - - return Collections.unmodifiableList(collectionNames); - } catch (SQLException e) { - throw new SKException("Failed to get collection names", e); - } - } - - /** - * Gets a list of records from the store. - * - * @param collectionName the collection name - * @param keys the keys - * @param recordDefinition the record definition - * @param mapper the mapper - * @param options the options - * @param the record type - * @return the records - * @throws SKException if an error occurs while getting the records - */ - @Override - public List getRecords(String collectionName, List keys, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper, - GetRecordOptions options) { - List fields; - if (options != null && options.isIncludeVectors()) { - fields = recordDefinition.getAllFields(); - } else { - fields = recordDefinition.getNonVectorFields(); - } - - String query; - - if (options != null && options.isWildcardKeyMatching()) { - if (keys.size() > 1) { - throw new SKException("If using wildcard key matching, only one key is allowed"); - } - query = "SELECT %s FROM %s WHERE %s LIKE (%s)"; - } else { - query = "SELECT %s FROM %s WHERE %s IN (%s)"; - } - - query = formatQuery(query, - getQueryColumnsFromFields(fields), - getCollectionTableName(collectionName), - getKeyColumnName(recordDefinition.getKeyField()), - getWildcardString(keys.size())); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (int i = 0; i < keys.size(); ++i) { - statement.setObject(i + 1, keys.get(i)); - } - - List records = new ArrayList<>(); - ResultSet resultSet = statement.executeQuery(); - - while (resultSet.next()) { - records.add(mapper.mapStorageModelToRecord(resultSet, options)); - } - - return Collections.unmodifiableList(records); - } catch (SQLException e) { - throw new SKException("Failed to set statement values", e); - } - } - - @Override - public void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition recordDefinition, UpsertRecordOptions options) { - throw new UnsupportedOperationException( - "Upsert is not supported. Try with a specific query provider."); - } - - /** - * Deletes records. - * - * @param collectionName the collection name - * @param keys the keys - * @param recordDefinition the record definition - * @param options the options - * @throws SKException if an error occurs while deleting the records - */ - @Override - public void deleteRecords(String collectionName, List keys, - VectorStoreRecordDefinition recordDefinition, DeleteRecordOptions options) { - String query = formatQuery("DELETE FROM %s WHERE %s IN (%s)", - getCollectionTableName(collectionName), - getKeyColumnName(recordDefinition.getKeyField()), - getWildcardString(keys.size())); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (int i = 0; i < keys.size(); ++i) { - statement.setObject(i + 1, keys.get(i)); - } - - statement.execute(); - } catch (SQLException e) { - throw new SKException("Failed to set statement values", e); - } - } - - protected List getRecordsWithFilter(String collectionName, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper, - GetRecordOptions options, - String filter, - List parameters) { - List fields; - if (options.isIncludeVectors()) { - fields = recordDefinition.getAllFields(); - } else { - fields = recordDefinition.getNonVectorFields(); - } - - String filterClause = filter == null || filter.isEmpty() ? "" : "WHERE " + filter; - String selectQuery = formatQuery("SELECT %s FROM %s %s", - getQueryColumnsFromFields(fields), - getCollectionTableName(collectionName), - filterClause); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(selectQuery)) { - if (parameters != null) { - for (int i = 0; i < parameters.size(); ++i) { - statement.setObject(i + 1, parameters.get(i)); - } - } - - List records = new ArrayList<>(); - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - records.add(mapper.mapStorageModelToRecord(resultSet, options)); - } - - return Collections.unmodifiableList(records); - } catch (SQLException e) { - throw new SKException("Failed to set statement values", e); - } - } - - /** - * Vector search. Executes a vector search query and returns the results. The results are mapped - * to the specified record type using the provided mapper. The query is executed against the - * specified collection. - * - * @param the record type - * @param collectionName the collection name - * @param vector the vector to search with - * @param options the search options - * @param recordDefinition the record definition - * @param mapper the mapper, responsible for mapping the result set to the record - * type. - * @return the search results - */ - @Override - public VectorSearchResults search(String collectionName, - List vector, VectorSearchOptions options, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper) { - if (recordDefinition.getVectorFields().isEmpty()) { - throw new SKException("No vector fields defined. Cannot perform vector search"); - } - - VectorStoreRecordVectorField firstVectorField = recordDefinition.getVectorFields() - .get(0); - if (options == null) { - options = VectorSearchOptions.createDefault(firstVectorField.getName()); - } - - VectorStoreRecordVectorField vectorField = options.getVectorFieldName() == null - ? firstVectorField - : (VectorStoreRecordVectorField) recordDefinition - .getField(options.getVectorFieldName()); - - String filter = getFilter(options.getVectorSearchFilter(), recordDefinition); - List parameters = getFilterParameters(options.getVectorSearchFilter()); - - List records = getRecordsWithFilter(collectionName, recordDefinition, mapper, - new GetRecordOptions(true), filter, parameters); - - DistanceFunction distanceFunction = vectorField - .getDistanceFunction() == DistanceFunction.UNDEFINED - ? DistanceFunction.EUCLIDEAN_DISTANCE - : vectorField.getDistanceFunction(); - - return new VectorSearchResults<>( - VectorOperations.exactSimilaritySearch(records, vector, vectorField, - distanceFunction, options)); - } - - /** - * Validates an SQL identifier. - * - * @param identifier the identifier - * @return the identifier if it is valid - * @throws SKException if the identifier is invalid - */ - public static String validateSQLidentifier(String identifier) { - if (identifier.matches("[a-zA-Z_][a-zA-Z0-9_]*")) { - return identifier; - } - throw new SKException("Invalid SQL identifier: " + identifier); - } - - /** - * Formats a query. - * - * @param query the query - * @param args the arguments - * @return the formatted query - */ - public String formatQuery(String query, String... args) { - return String.format(query, (Object[]) args); - } - - /** - * Gets the filter query string for the given vector search filter and record definition. - * - * @param filter The filter to get the filter string for. - * @param recordDefinition The record definition to get the filter string for. - * @return The filter string. - */ - @Override - public String getFilter(VectorSearchFilter filter, - VectorStoreRecordDefinition recordDefinition) { - if (filter == null - || filter.getFilterClauses().isEmpty()) { - return ""; - } - - return filter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - return getEqualToFilter(new EqualToFilterClause( - recordDefinition.getField(equalToFilterClause.getFieldName()) - .getEffectiveStorageName(), - equalToFilterClause.getValue())); - } else if (filterClause instanceof AnyTagEqualToFilterClause) { - AnyTagEqualToFilterClause anyTagEqualToFilterClause = (AnyTagEqualToFilterClause) filterClause; - return getAnyTagEqualToFilter(new AnyTagEqualToFilterClause( - recordDefinition.getField(anyTagEqualToFilterClause.getFieldName()) - .getEffectiveStorageName(), - anyTagEqualToFilterClause.getValue())); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.joining(" AND ")); - } - - /** - * Gets the filter parameters for the given vector search filter to associate with the filter - * string generated by the getFilter method. - * - * @param filter The filter to get the filter parameters for. - * @return The filter parameters. - */ - @Override - public List getFilterParameters(VectorSearchFilter filter) { - if (filter == null - || filter.getFilterClauses().isEmpty()) { - return Collections.emptyList(); - } - - return filter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - return equalToFilterClause.getValue(); - } else if (filterClause instanceof AnyTagEqualToFilterClause) { - AnyTagEqualToFilterClause anyTagEqualToFilterClause = (AnyTagEqualToFilterClause) filterClause; - return String.format("%%\"%s\"%%", anyTagEqualToFilterClause.getValue()); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.toList()); - } - - @Override - public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(filterClause.getFieldName()); - Object value = filterClause.getValue(); - - if (value instanceof String) { - return String.format("%s = ?", fieldName); - } else if (value instanceof Boolean) { - return String.format("%s = ?", fieldName); - } else if (value instanceof Integer) { - return String.format("%s = ?", fieldName); - } else if (value instanceof Long) { - return String.format("%s = ?", fieldName); - } else if (value instanceof Float) { - return String.format("%s = ?", fieldName); - } else if (value instanceof Double) { - return String.format("%s = ?", fieldName); - } else if (value instanceof OffsetDateTime) { - return String.format("%s = ?", fieldName); - } else { - throw new SKException("Unsupported filter value type '" - + value.getClass().getSimpleName() + "'."); - } - } - - @Override - public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - String fieldName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(filterClause.getFieldName()); - - return String.format("%s LIKE ?", fieldName); - } - - @Override - public VectorStoreRecordMapper getVectorStoreRecordMapper( - Class recordClass, - VectorStoreRecordDefinition recordDefinition) { - return JDBCVectorStoreRecordMapper.builder() - .withRecordClass(recordClass) - .withVectorStoreRecordDefinition(recordDefinition) - .build(); - } - - /** - * The builder for {@link JDBCVectorStoreQueryProvider}. - */ - public static class Builder - implements SQLVectorStoreQueryProvider.Builder { - - private DataSource dataSource; - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - - /** - * Sets the data source. - * - * @param dataSource the data source - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * - * @param collectionsTable the collections table name - * @return the builder - */ - public Builder withCollectionsTable(String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - @Override - public JDBCVectorStoreQueryProvider build() { - if (dataSource == null) { - throw new SKException("DataSource is required"); - } - - return new JDBCVectorStoreQueryProvider(dataSource, collectionsTable, - prefixForCollectionTables); - } - } - -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java deleted file mode 100644 index 1d6b3e09b..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.lang.reflect.Field; -import java.sql.ResultSet; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.sql.DataSource; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -/** - * The JDBCVectorStoreRecordCollection class represents a collection of records in a JDBC vector - * store. It implements the SQLVectorStoreRecordCollection interface and provides methods for - * managing the collection, such as creating, deleting, and upserting records. - * - * @param the type of the records in the collection - */ -public class JDBCVectorStoreRecordCollection - implements SQLVectorStoreRecordCollection { - - private final String collectionName; - protected final VectorStoreRecordDefinition recordDefinition; - protected final VectorStoreRecordMapper vectorStoreRecordMapper; - private final JDBCVectorStoreRecordCollectionOptions options; - protected final SQLVectorStoreQueryProvider queryProvider; - - /** - * Creates a new instance of the {@link JDBCVectorStoreRecordCollection}. - * - * @param dataSource the data source - * @param collectionName the name of the collection - * @param options the options - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed - public JDBCVectorStoreRecordCollection( - @Nonnull DataSource dataSource, - @Nonnull String collectionName, - @Nonnull JDBCVectorStoreRecordCollectionOptions options) { - this.collectionName = collectionName; - this.options = options; - - // If record definition is not provided, create one from the record class - recordDefinition = options.getRecordDefinition() == null - ? VectorStoreRecordDefinition.fromRecordClass(options.getRecordClass()) - : options.getRecordDefinition(); - - // If the query provider is not provided, set a default one - if (options.getQueryProvider() == null) { - this.queryProvider = JDBCVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - } else { - this.queryProvider = options.getQueryProvider(); - } - - // If mapper is not provided, set a default one - if (options.getVectorStoreRecordMapper() == null) { - vectorStoreRecordMapper = options.getQueryProvider() - .getVectorStoreRecordMapper(options.getRecordClass(), - recordDefinition); - } else { - vectorStoreRecordMapper = options.getVectorStoreRecordMapper(); - } - - // Check if the types are supported - queryProvider.validateSupportedTypes(recordDefinition); - } - - /** - * Gets the name of the collection. - * - * @return The name of the collection. - */ - @Override - public String getCollectionName() { - return collectionName; - } - - /** - * Checks if the collection exists in the store. - * - * @return A Mono emitting a boolean indicating if the collection exists. - * @throws SKException if the operation fails - */ - @Override - public Mono collectionExistsAsync() { - return Mono.fromCallable( - () -> queryProvider.collectionExists(this.collectionName)) - .subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Creates the collection in the store. - * - * @return A Mono representing the completion of the creation operation. - * @throws SKException if the operation fails - */ - @Override - public Mono> createCollectionAsync() { - return Mono.fromRunnable( - () -> queryProvider.createCollection(this.collectionName, recordDefinition)) - .subscribeOn(Schedulers.boundedElastic()) - .then(Mono.just(this)); - } - - /** - * Creates the collection in the store if it does not exist. - * - * @return A Mono representing the completion of the creation operation. - * @throws SKException if the operation fails - */ - @Override - public Mono> createCollectionIfNotExistsAsync() { - return collectionExistsAsync().map( - exists -> { - if (!exists) { - return createCollectionAsync(); - } - return Mono.empty(); - }) - .flatMap(mono -> mono) - .then(Mono.just(this)); - } - - /** - * Deletes the collection from the store. - * - * @return A Mono representing the completion of the deletion operation. - * @throws SKException if the operation fails - */ - @Override - public Mono deleteCollectionAsync() { - return Mono.fromRunnable( - () -> { - queryProvider.deleteCollection(this.collectionName); - }).subscribeOn(Schedulers.boundedElastic()).then(); - } - - /** - * Gets a record from the store. - * - * @param key The key of the record to get. - * @param options The options for getting the record. - * @return A Mono emitting the record. - * @throws SKException if the operation fails - */ - @Override - public Mono getAsync(String key, GetRecordOptions options) { - Objects.requireNonNull(key, "key is required"); - - return this.getBatchAsync(Collections.singletonList(key), options) - .mapNotNull(records -> { - if (records.isEmpty()) { - return null; - } - return records.get(0); - }); - } - - /** - * Gets a batch of records from the store. - * - * @param keys The keys of the records to get. - * @param options The options for getting the records. - * @return A Mono emitting a collection of records. - * @throws SKException if the operation fails - */ - @Override - public Mono> getBatchAsync(@Nonnull List keys, GetRecordOptions options) { - Objects.requireNonNull(keys, "keys is required"); - - return Mono.fromCallable( - () -> queryProvider.getRecords(this.collectionName, keys, recordDefinition, - vectorStoreRecordMapper, options)) - .subscribeOn(Schedulers.boundedElastic()); - } - - protected String getKeyFromRecord(Record data) { - try { - Field keyField = data.getClass() - .getDeclaredField(recordDefinition.getKeyField().getName()); - keyField.setAccessible(true); - return keyField.get(data).toString(); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new SKException("Failed to get key from record", e); - } - } - - /** - * Inserts or updates a record in the store. - * - * @param data The record to upsert. - * @param options The options for upserting the record. - * @return A Mono emitting the key of the upserted record. - * @throws SKException if the operation fails - */ - @Override - public Mono upsertAsync(Record data, UpsertRecordOptions options) { - Objects.requireNonNull(data, "data is required"); - - return this.upsertBatchAsync(Collections.singletonList(data), options) - .mapNotNull(keys -> { - if (keys.isEmpty()) { - return null; - } - return keys.get(0); - }); - } - - /** - * Inserts or updates a batch of records in the store. - * - * @param data The records to upsert. - * @param options The options for upserting the records. - * @return A Mono emitting a collection of keys of the upserted records. - * @throws SKException if the operation fails - */ - @Override - public Mono> upsertBatchAsync(List data, UpsertRecordOptions options) { - Objects.requireNonNull(data, "data is required"); - - return Mono.fromCallable( - () -> { - queryProvider.upsertRecords(this.collectionName, data, recordDefinition, options); - return data.stream().map(this::getKeyFromRecord).collect(Collectors.toList()); - }) - .subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Deletes a record from the store. - * - * @param key The key of the record to delete. - * @param options The options for deleting the record. - * @return A Mono representing the completion of the deletion operation. - * @throws SKException if the operation fails - */ - @Override - public Mono deleteAsync(String key, DeleteRecordOptions options) { - return this.deleteBatchAsync(Collections.singletonList(key), options); - } - - /** - * Deletes a batch of records from the store. - * - * @param keys The keys of the records to delete. - * @param options The options for deleting the records. - * @return A Mono representing the completion of the deletion operation. - * @throws SKException if the operation fails - */ - @Override - public Mono deleteBatchAsync(List keys, DeleteRecordOptions options) { - return Mono.fromRunnable( - () -> { - queryProvider.deleteRecords(this.collectionName, keys, recordDefinition, options); - }).subscribeOn(Schedulers.boundedElastic()).then(); - } - - /** - * Prepares the collection for use. - * - * @return A Mono representing the completion of the preparation operation. - * @throws SKException if the operation fails - */ - @Override - public Mono prepareAsync() { - return Mono.fromRunnable(queryProvider::prepareVectorStore) - .subscribeOn(Schedulers.boundedElastic()).then(); - } - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param vectorSearchOptions The options to use for the search. - * @return A list of search results. - */ - @Override - public Mono> searchAsync(List vector, - VectorSearchOptions vectorSearchOptions) { - return Mono.fromCallable( - () -> queryProvider.search(this.collectionName, vector, vectorSearchOptions, - recordDefinition, - vectorStoreRecordMapper)) - .subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Builder for a JDBCVectorStoreRecordCollection. - * - * @param the type of the records in the collection - */ - public static class Builder - implements SemanticKernelBuilder> { - - private DataSource dataSource; - private String collectionName; - private JDBCVectorStoreRecordCollectionOptions options; - - /** - * Sets the data source. - * - * @param dataSource the data source - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collection name. - * - * @param collectionName the collection name - * @return the builder - */ - public Builder withCollectionName(String collectionName) { - this.collectionName = collectionName; - return this; - } - - /** - * Sets the options. - * - * @param options the options - * @return the builder - */ - public Builder withOptions(JDBCVectorStoreRecordCollectionOptions options) { - this.options = options; - return this; - } - - @Override - public JDBCVectorStoreRecordCollection build() { - if (dataSource == null) { - throw new SKException("dataSource is required"); - } - if (collectionName == null) { - throw new SKException("collectionName is required"); - } - if (options == null) { - throw new SKException("options is required"); - } - - return new JDBCVectorStoreRecordCollection<>(dataSource, collectionName, options); - } - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionFactory.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionFactory.java deleted file mode 100644 index 796f0720c..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; - -import javax.sql.DataSource; - -/** - * Factory for creating JDBC vector store record collections. - */ -public interface JDBCVectorStoreRecordCollectionFactory { - - /** - * Creates a new JDBC vector store record collection. - * - * @param dataSource The JDBC data source. - * @param collectionName The name of the collection. - * @param recordClass The class type of the - * @param recordDefinition The record definition. - * @param The type of record in the collection. - * @return The new JDBC vector store record collection. - */ - JDBCVectorStoreRecordCollection createVectorStoreRecordCollection( - DataSource dataSource, - String collectionName, - Class recordClass, - VectorStoreRecordDefinition recordDefinition); -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionOptions.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionOptions.java deleted file mode 100644 index 596d0f298..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.sql.ResultSet; - -import static com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider.DEFAULT_COLLECTIONS_TABLE; -import static com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider.DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - -/** - * Options for a JDBC vector store record collection. - * @param the record type - */ -public class JDBCVectorStoreRecordCollectionOptions - implements VectorStoreRecordCollectionOptions { - private final Class recordClass; - private final VectorStoreRecordMapper vectorStoreRecordMapper; - private final VectorStoreRecordDefinition recordDefinition; - private final SQLVectorStoreQueryProvider queryProvider; - private final String collectionsTableName; - private final String prefixForCollectionTables; - - private JDBCVectorStoreRecordCollectionOptions( - Class recordClass, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper vectorStoreRecordMapper, - SQLVectorStoreQueryProvider queryProvider, - String collectionsTableName, - String prefixForCollectionTables) { - this.recordClass = recordClass; - this.recordDefinition = recordDefinition; - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - this.queryProvider = queryProvider; - this.collectionsTableName = collectionsTableName; - this.prefixForCollectionTables = prefixForCollectionTables; - } - - /** - * Creates a new builder. - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Gets the key class. - * - * @return the key class - */ - @Override - public Class getKeyClass() { - return String.class; - } - - /** - * Gets the record class. - * @return the record class - */ - public Class getRecordClass() { - return recordClass; - } - - /** - * Gets the record definition. - * @return the record definition - */ - public VectorStoreRecordDefinition getRecordDefinition() { - return recordDefinition; - } - - /** - * Gets the vector store record mapper. - * @return the vector store record mapper - */ - public VectorStoreRecordMapper getVectorStoreRecordMapper() { - return vectorStoreRecordMapper; - } - - /** - * Gets the collections table. - * @return the collections table - */ - public String getCollectionsTableName() { - return collectionsTableName; - } - - /** - * Gets the prefix for collection tables. - * @return the prefix for collection tables - */ - public String getPrefixForCollectionTables() { - return prefixForCollectionTables; - } - - /** - * Gets the query provider. - * @return the query provider - */ - @SuppressFBWarnings("EI_EXPOSE_REP") // DataSource in queryProvider is not exposed - public SQLVectorStoreQueryProvider getQueryProvider() { - return queryProvider; - } - - /** - * Builder for JDBC vector store record collection options. - * @param the record type - */ - public static class Builder { - private Class recordClass; - private VectorStoreRecordDefinition recordDefinition; - private VectorStoreRecordMapper vectorStoreRecordMapper; - private SQLVectorStoreQueryProvider queryProvider; - private String collectionsTableName = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - - /** - * Sets the record class. - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the record definition. - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets the vector store record mapper. - * @param vectorStoreRecordMapper the vector store record mapper - * @return the builder - */ - public Builder withVectorStoreRecordMapper( - VectorStoreRecordMapper vectorStoreRecordMapper) { - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - return this; - } - - /** - * Sets the query provider. - * @param queryProvider the query provider - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource in queryProvider is not exposed - public Builder withQueryProvider(SQLVectorStoreQueryProvider queryProvider) { - this.queryProvider = queryProvider; - return this; - } - - /** - * Sets the collections table name. - * @param collectionsTableName the collections table name - * @return the builder - */ - public Builder withCollectionsTableName(String collectionsTableName) { - this.collectionsTableName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(collectionsTableName); - return this; - } - - /** - * Sets the prefix for collection tables. - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = JDBCVectorStoreQueryProvider - .validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Builds the options. - * @return the options - */ - public JDBCVectorStoreRecordCollectionOptions build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - - return new JDBCVectorStoreRecordCollectionOptions<>( - recordClass, - recordDefinition, - vectorStoreRecordMapper, - queryProvider, - collectionsTableName, - prefixForCollectionTables); - } - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordMapper.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordMapper.java deleted file mode 100644 index b52071cf8..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordMapper.java +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.util.List; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.function.BiFunction; - -/** - * Maps a JDBC result set to a record. - * - * @param the record type - */ -public class JDBCVectorStoreRecordMapper - extends VectorStoreRecordMapper { - - /** - * Constructs a new instance of the VectorStoreRecordMapper. - * - * @param storageModelToRecordMapper the function to convert a storage model to a record - */ - protected JDBCVectorStoreRecordMapper( - BiFunction storageModelToRecordMapper) { - super(null, storageModelToRecordMapper); - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Operation not supported. - */ - @Override - public ResultSet mapRecordToStorageModel(Record record) { - throw new UnsupportedOperationException("Not implemented"); - } - - /** - * Builder for {@link JDBCVectorStoreRecordMapper}. - * - * @param the record type - */ - public static class Builder - implements SemanticKernelBuilder> { - private Class recordClass; - private VectorStoreRecordDefinition vectorStoreRecordDefinition; - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record definition. - * - * @param vectorStoreRecordDefinition the vector store record definition - * @return the builder - */ - public Builder withVectorStoreRecordDefinition( - VectorStoreRecordDefinition vectorStoreRecordDefinition) { - this.vectorStoreRecordDefinition = vectorStoreRecordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the {@link JDBCVectorStoreRecordMapper}. - * - * @return the {@link JDBCVectorStoreRecordMapper} - */ - public JDBCVectorStoreRecordMapper build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - if (vectorStoreRecordDefinition == null) { - throw new SKException("vectorStoreRecordDefinition is required"); - } - - return new JDBCVectorStoreRecordMapper<>( - (resultSet, options) -> { - try { - // Create an ObjectNode to hold the values - ObjectNode objectNode = objectMapper.createObjectNode(); - - // Select fields from the record definition. - List fields; - if (options != null && options.isIncludeVectors()) { - fields = vectorStoreRecordDefinition.getAllFields(); - } else { - fields = vectorStoreRecordDefinition.getNonVectorFields(); - } - - for (VectorStoreRecordField field : fields) { - Object value = resultSet.getObject(field.getEffectiveStorageName()); - Class fieldType = field.getFieldType(); - - if (field instanceof VectorStoreRecordVectorField) { - // If the vector field is other than String, deserialize it from the JSON string - if (!fieldType.equals(String.class)) { - value = objectMapper.readValue((String) value, fieldType); - } - } else if (field instanceof VectorStoreRecordDataField) { - // If the field is List, deserialize it from the JSON string - if (fieldType.equals(List.class)) { - value = objectMapper.readValue((String) value, fieldType); - } - } - - JsonNode genericNode = objectMapper.valueToTree(value); - objectNode.set(field.getEffectiveStorageName(), genericNode); - } - - // Deserialize the object node to the record class - return objectMapper.convertValue(objectNode, recordClass); - } catch (SQLException | JsonProcessingException e) { - throw new SKException( - "Failure to serialize object, by default the JDBC connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }); - } - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStore.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStore.java deleted file mode 100644 index 08d167b8f..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStore.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStore; -import reactor.core.publisher.Mono; - -/** - * Represents a SQL vector store. - */ -public interface SQLVectorStore - extends VectorStore { - - /** - * Prepares the vector store. - * - * @return A {@link Mono} that completes when the vector store is prepared to be used. - */ - Mono prepareAsync(); -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreFilterQueryProvider.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreFilterQueryProvider.java deleted file mode 100644 index 4feb272f3..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreFilterQueryProvider.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.filter.FilterMapping; - -import java.util.List; - -public interface SQLVectorStoreFilterQueryProvider extends FilterMapping { - /** - * Gets the filter parameters for the given vector search filter to associate with the filter string - * generated by the getFilter method. - * - * @param filter The filter to get the filter parameters for. - * @return The filter parameters. - */ - List getFilterParameters(VectorSearchFilter filter); -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreQueryProvider.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreQueryProvider.java deleted file mode 100644 index 30a535fb0..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreQueryProvider.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; - -import java.sql.ResultSet; -import java.util.List; -import java.util.Map; - -/** - * The JDBC vector store query provider. - * Provides the necessary methods to interact with a JDBC vector store and vector store collections. - */ -public interface SQLVectorStoreQueryProvider { - /** - * The default name for the collections table. - */ - String DEFAULT_COLLECTIONS_TABLE = "SKCollections"; - - /** - * The prefix for collection tables. - */ - String DEFAULT_PREFIX_FOR_COLLECTION_TABLES = "SKCollection_"; - - /** - * Gets the supported key types and their corresponding SQL types. - * - * @return the supported key types - */ - Map, String> getSupportedKeyTypes(); - - /** - * Gets the supported data types and their corresponding SQL types. - * - * @return the supported data types - */ - Map, String> getSupportedDataTypes(); - - /** - * Gets the supported vector types and their corresponding SQL types. - * - * @return the supported vector types - */ - Map, String> getSupportedVectorTypes(); - - /** - * Prepares the vector store. - * Executes any necessary setup steps for the vector store. - */ - void prepareVectorStore(); - - /** - * Checks if the types of the record class fields are supported. - * - * @param recordDefinition the record definition - */ - void validateSupportedTypes(VectorStoreRecordDefinition recordDefinition); - - /** - * Checks if a collection exists. - * - * @param collectionName the collection name - * @return true if the collection exists, false otherwise - */ - boolean collectionExists(String collectionName); - - /** - * Creates a collection. - * - * @param collectionName the collection name - * @param recordDefinition the record definition - */ - void createCollection(String collectionName, VectorStoreRecordDefinition recordDefinition); - - /** - * Deletes a collection. - * - * @param collectionName the collection name - */ - void deleteCollection(String collectionName); - - /** - * Gets the collection names. - * - * @return the collection names - */ - List getCollectionNames(); - - /** - * Gets records. - * - * @param collectionName the collection name - * @param keys the keys - * @param recordDefinition the record definition - * @param mapper the mapper - * @param options the options - * @param the record type - * @return the records - */ - List getRecords(String collectionName, List keys, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper, - GetRecordOptions options); - - /** - * Upserts records. - * - * @param collectionName the collection name - * @param records the records - * @param vectorStoreRecordDefinition the record definition - * @param options the options - */ - void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition vectorStoreRecordDefinition, UpsertRecordOptions options); - - /** - * Deletes records. - * - * @param collectionName the collection name - * @param keys the keys - * @param recordDefinition the record definition - * @param options the options - */ - void deleteRecords(String collectionName, List keys, - VectorStoreRecordDefinition recordDefinition, DeleteRecordOptions options); - - /** - * Vector search. - * Executes a vector search query and returns the results. - * The results are mapped to the specified record type using the provided mapper. - * The query is executed against the specified collection. - * - * @param the record type - * @param collectionName the collection name - * @param vector the vector to search with - * @param options the vector search options - * @param recordDefinition the record definition - * @param mapper the mapper, responsible for mapping the result set to the record type. - * @return the search results - */ - VectorSearchResults search(String collectionName, - List vector, - VectorSearchOptions options, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper); - - /** - * Gets the record mapper for the given record class and definition. - * - * @param the record type - * @param recordClass the record class - * @param recordDefinition the record definition - * @return the record mapper that maps JDBC result sets to the given record. - */ - VectorStoreRecordMapper getVectorStoreRecordMapper( - final Class recordClass, - final VectorStoreRecordDefinition recordDefinition); - - /** - * The builder for the JDBC vector store query provider. - */ - interface Builder extends SemanticKernelBuilder { - - } -} diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreRecordCollection.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreRecordCollection.java deleted file mode 100644 index 03fe3e074..000000000 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/SQLVectorStoreRecordCollection.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import reactor.core.publisher.Mono; - -/** - * Represents a SQL vector store record collection. - * - * @param the key type - * @param the record type - */ -public interface SQLVectorStoreRecordCollection - extends VectorStoreRecordCollection { - - /** - * Prepares the vector store record collection. - * - * @return A {@link Mono} that completes when the vector store record collection is prepared to be used. - */ - Mono prepareAsync(); -} diff --git a/data/semantickernel-data-mysql/pom.xml b/data/semantickernel-data-mysql/pom.xml deleted file mode 100644 index 3d6d40e6b..000000000 --- a/data/semantickernel-data-mysql/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-data-mysql - Semantic Kernel MySQL connector - Provides a MySQL connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.spotbugs - spotbugs-annotations - - - \ No newline at end of file diff --git a/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java b/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java deleted file mode 100644 index feb6dc4f3..000000000 --- a/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.mysql; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import java.util.stream.Collectors; - -/** - * The MySQL vector store query provider. - * Provides the necessary methods to interact with a MySQL - * vector store and vector store collections. - */ -public class MySQLVectorStoreQueryProvider extends - JDBCVectorStoreQueryProvider implements SQLVectorStoreQueryProvider { - - private final ObjectMapper objectMapper; - - @SuppressFBWarnings("EI_EXPOSE_REP2") - private MySQLVectorStoreQueryProvider( - @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables, - @Nonnull ObjectMapper objectMapper) { - super(dataSource, collectionsTable, prefixForCollectionTables); - this.objectMapper = objectMapper; - } - - /** - * Creates a new builder. - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - private void setUpsertStatementValues(PreparedStatement statement, Object record, - List fields) { - JsonNode jsonNode = objectMapper.valueToTree(record); - - for (int i = 0; i < fields.size(); ++i) { - VectorStoreRecordField field = fields.get(i); - try { - JsonNode valueNode = jsonNode.get(field.getEffectiveStorageName()); - - if (field instanceof VectorStoreRecordVectorField) { - // Convert the vector field to a string - if (!field.getFieldType().equals(String.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } else if (field instanceof VectorStoreRecordDataField) { - // Convert List field to a string - if (field.getFieldType().equals(List.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } - - statement.setObject(i + 1, - objectMapper.convertValue(valueNode, field.getFieldType())); - } catch (SQLException | JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - /** - * Upserts records into the collection. - * @param collectionName the collection name - * @param records the records to upsert - * @param recordDefinition the record definition - * @param options the upsert options - * @throws SKException if the upsert fails - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") // SQL query is generated dynamically with valid identifiers - public void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition recordDefinition, UpsertRecordOptions options) { - List fields = recordDefinition.getAllFields(); - - String onDuplicateKeyUpdate = fields.stream() - .map(field -> formatQuery("%s = VALUES(%s)", - validateSQLidentifier(field.getEffectiveStorageName()), - field.getEffectiveStorageName())) - .collect(Collectors.joining(", ")); - - String query = formatQuery("INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s", - getCollectionTableName(collectionName), - getQueryColumnsFromFields(fields), - getWildcardString(fields.size()), - onDuplicateKeyUpdate); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (Object record : records) { - setUpsertStatementValues(statement, record, recordDefinition.getAllFields()); - statement.addBatch(); - } - - statement.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to upsert records", e); - } - } - - /** - * The MySQL vector store query provider builder. - */ - public static class Builder - extends JDBCVectorStoreQueryProvider.Builder { - private DataSource dataSource; - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - private ObjectMapper objectMapper = new ObjectMapper(); - - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * @param collectionsTable the collections table name - * @return the builder - */ - public Builder withCollectionsTable(String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Sets the object mapper. - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - public MySQLVectorStoreQueryProvider build() { - if (dataSource == null) { - throw new SKException("DataSource is required"); - } - - return new MySQLVectorStoreQueryProvider(dataSource, collectionsTable, - prefixForCollectionTables, objectMapper); - } - } -} diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml deleted file mode 100644 index e2c934439..000000000 --- a/data/semantickernel-data-oracle/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-data-oracle - Semantic Kernel Oracle connector - Provides a Oracle connector for the Semantic Kernel - - - 1.21.4 - - - - - - org.testcontainers - testcontainers-bom - ${testcontainers.version} - pom - import - - - - - - - com.microsoft.semantic-kernel - semantickernel-api-data - provided - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - provided - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.oracle.database.jdbc - ojdbc11 - 23.7.0.25.01 - - - com.oracle.database.jdbc - ojdbc-provider-jackson-oson - 1.0.4 - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.testcontainers - testcontainers - test - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - oracle-free - test - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - - - android - test - - check - - - - - true - - - - com.diffplug.spotless - spotless-maven-plugin - - true - - - - - \ No newline at end of file diff --git a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleDataTypesMapping.java b/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleDataTypesMapping.java deleted file mode 100644 index 1d5db527f..000000000 --- a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleDataTypesMapping.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -/** - * Defines oracle database type constants for supported java types. - */ -public class OracleDataTypesMapping { - - /** - * Oracle database type used when strings are mapped to VARCHAR - */ - public static final String STRING_VARCHAR = "VARCHAR2(%s)"; - /** - * Oracle database type used when strings are mapped to CLOB - */ - public static final String STRING_CLOB = "CLOB"; - /** - * Oracle database type used to map booleans - */ - public static final String BOOLEAN = "BOOLEAN"; - /** - * Oracle database type used to map bytes - */ - public static final String BYTE = "NUMBER(3)"; - /** - * Oracle database type used to map byte arrays - */ - public static final String BYTE_ARRAY = "RAW(2000)"; - /** - * Oracle database type used to map shorts - */ - public static final String SHORT = "NUMBER(5)"; - /** - * Oracle database type used to map ints - */ - public static final String INTEGER = "NUMBER(10)"; - /** - * Oracle database type used to map longs - */ - public static final String LONG = "NUMBER(19)"; - /** - * Oracle database type used to map float - */ - public static final String FLOAT = "BINARY_FLOAT"; - /** - * Oracle database type used to map double - */ - public static final String DOUBLE = "BINARY_DOUBLE"; - /** - * Oracle database type used to map BigDecimal - */ - public static final String DECIMAL = "NUMBER"; - /** - * Oracle database type used to map offset date time - */ - public static final String OFFSET_DATE_TIME = "TIMESTAMP(9) WITH TIME ZONE"; - /** - * Oracle database type used to map UUID - */ - public static final String UUID = "VARCHAR2(36)"; - /** - * Oracle database type used to map lists - */ - public static final String JSON = "JSON"; - /** - * Oracle database type used to map vectors (the parameter is the dimension of the vector) - */ - public static final String VECTOR_FLOAT = "VECTOR(%s, FLOAT32)"; -} diff --git a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreFieldHelper.java b/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreFieldHelper.java deleted file mode 100644 index bf4dd2952..000000000 --- a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreFieldHelper.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.jdbc.oracle.OracleVectorStoreQueryProvider.StringTypeMapping; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.exceptions.SKException; -import java.math.BigDecimal; -import java.time.OffsetDateTime; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * Helper class for field operations. Handles mapping between field java types to DB types and - * generating SQL statement to create field indexes. - */ -class OracleVectorStoreFieldHelper { - - /** - * Object naming regular expression - */ - private static final String OBJECT_NAMING_REGEXP = "[a-zA-Z_][a-zA-Z0-9_]{1,128}"; - /** - * The logger - */ - private static final Logger LOGGER = Logger.getLogger(OracleVectorStoreFieldHelper.class.getName()); - - /** - * Maps supported key java classes to Oracle database types - */ - private static final HashMap, String> supportedKeyTypes = new HashMap(); - static { - supportedKeyTypes.put(String.class, String.format(OracleDataTypesMapping.STRING_VARCHAR, 255)); - } - - /** - * Maps supported vector java classes to Oracle database types - */ - private static final Map, String> supportedVectorTypes = new HashMap(); - static { - supportedVectorTypes.put(String.class, OracleDataTypesMapping.VECTOR_FLOAT); - supportedVectorTypes.put(List.class, OracleDataTypesMapping.VECTOR_FLOAT); - supportedVectorTypes.put(Collection.class, OracleDataTypesMapping.VECTOR_FLOAT); - supportedVectorTypes.put(float[].class, OracleDataTypesMapping.VECTOR_FLOAT); - supportedVectorTypes.put(Float[].class, OracleDataTypesMapping.VECTOR_FLOAT); - } - - /** - * Maps supported data java classes to Oracle database types - */ - private static final HashMap, String> supportedDataTypes = new HashMap(); - static { - supportedDataTypes.put(byte.class, OracleDataTypesMapping.BYTE); - supportedDataTypes.put(Byte.class, OracleDataTypesMapping.BYTE); - supportedDataTypes.put(short.class, OracleDataTypesMapping.SHORT); - supportedDataTypes.put(Short.class, OracleDataTypesMapping.SHORT); - supportedDataTypes.put(int.class, OracleDataTypesMapping.INTEGER); - supportedDataTypes.put(Integer.class, OracleDataTypesMapping.INTEGER); - supportedDataTypes.put(long.class, OracleDataTypesMapping.LONG); - supportedDataTypes.put(Long.class, OracleDataTypesMapping.LONG); - supportedDataTypes.put(Float.class, OracleDataTypesMapping.FLOAT); - supportedDataTypes.put(float.class, OracleDataTypesMapping.FLOAT); - supportedDataTypes.put(Double.class, OracleDataTypesMapping.DOUBLE); - supportedDataTypes.put(double.class, OracleDataTypesMapping.DOUBLE); - supportedDataTypes.put(BigDecimal.class, OracleDataTypesMapping.DECIMAL); - supportedDataTypes.put(Boolean.class, OracleDataTypesMapping.BOOLEAN); - supportedDataTypes.put(boolean.class, OracleDataTypesMapping.BOOLEAN); - supportedDataTypes.put(OffsetDateTime.class, OracleDataTypesMapping.OFFSET_DATE_TIME); - supportedDataTypes.put(UUID.class, OracleDataTypesMapping.UUID); - supportedDataTypes.put(byte[].class, OracleDataTypesMapping.BYTE_ARRAY); - supportedDataTypes.put(List.class, OracleDataTypesMapping.JSON); - } - - /** - * Suffix added to the effective column name to generate the index name for a vector column. - */ - public static final String VECTOR_INDEX_SUFFIX = "_VECTOR_INDEX"; - - /** - * Gets the mapping between the supported Java key types and the Oracle database type. - * - * @return the mapping between the supported Java key types and the Oracle database type. - */ - static Map, String> getSupportedKeyTypes() { - - return Collections.unmodifiableMap(supportedKeyTypes); - } - - /** - * Gets the mapping between the supported Java data types and the Oracle database type. - * - * @return the mapping between the supported Java data types and the Oracle database type. - */ - static Map, String> getSupportedDataTypes( - StringTypeMapping stringTypeMapping, int defaultVarCharLength) { - String stringType = stringTypeMapping.equals(StringTypeMapping.USE_VARCHAR) - ? String.format(OracleDataTypesMapping.STRING_VARCHAR, defaultVarCharLength) - : OracleDataTypesMapping.STRING_CLOB; - supportedDataTypes.put(String.class, stringType); - LOGGER.finest("Mapping String columns to " + stringType); - return Collections.unmodifiableMap(supportedDataTypes); - } - - /** - * Gets the mapping between the supported Java data types and the Oracle database type. - * - * @return the mapping between the supported Java data types and the Oracle database type. - */ - static Map, String> getSupportedVectorTypes() { - - return Collections.unmodifiableMap(supportedVectorTypes); - } - - /** - * Generates the statement to create the index according to the vector field definition. - * - * @return the CREATE VECTOR INDEX statement to create the index according to the vector - * field definition. - */ - static String getCreateVectorIndexStatement(VectorStoreRecordVectorField field, String collectionTableName) { - switch (field.getIndexKind()) { - case IVFFLAT: - return "CREATE VECTOR INDEX IF NOT EXISTS " - + validateObjectNaming(getIndexName(field.getEffectiveStorageName())) - + " ON " - + validateObjectNaming(collectionTableName) - + "( " + validateObjectNaming(field.getEffectiveStorageName()) + " ) " - + " ORGANIZATION NEIGHBOR PARTITIONS " - + " WITH DISTANCE COSINE " - + "PARAMETERS ( TYPE IVF )"; - case HNSW: - return "CREATE VECTOR INDEX IF NOT EXISTS " - + validateObjectNaming(getIndexName(field.getEffectiveStorageName())) - + " ON " - + validateObjectNaming(collectionTableName) - + "( " + validateObjectNaming(field.getEffectiveStorageName()) + " ) " - + "ORGANIZATION INMEMORY GRAPH " - + "WITH DISTANCE COSINE " - + "PARAMETERS (TYPE HNSW)"; - case UNDEFINED: - return null; - default: - LOGGER.warning("Unsupported index kind: " + field.getIndexKind()); - return null; - } - } - - /** - * Generates the statement to create the index according to the field definition. - * - * @return the CREATE INDEX statement to create the index according to the field definition. - */ - static String createIndexForDataField(String collectionTableName, VectorStoreRecordDataField dataField, Map, String> supportedDataTypes) { - if (supportedDataTypes.get(dataField.getFieldType()) == "JSON") { - String dataFieldIndex = "CREATE MULTIVALUE INDEX IF NOT EXISTS %s ON %s t (t.%s.%s)"; - return String.format(dataFieldIndex, - validateObjectNaming(collectionTableName + "_" + dataField.getEffectiveStorageName()), - validateObjectNaming(collectionTableName), - validateObjectNaming(dataField.getEffectiveStorageName()), - getFunctionForType(supportedDataTypes.get(dataField.getFieldSubType()))); - } else { - String dataFieldIndex = "CREATE INDEX IF NOT EXISTS %s ON %s (%s ASC)"; - return String.format(dataFieldIndex, - validateObjectNaming(collectionTableName + "_" + dataField.getEffectiveStorageName()), - validateObjectNaming(collectionTableName), - validateObjectNaming(dataField.getEffectiveStorageName()) - ); - } - } - - /** - * Returns vector columns names and types for CREATE TABLE statement - * @param fields list of vector record fields. - * @return comma separated list of columns and types for CREATE TABLE statement. - */ - static String getVectorColumnNamesAndTypes(List fields) { - List columns = fields.stream() - .map(field -> validateObjectNaming(field.getEffectiveStorageName()) + " " + - OracleVectorStoreFieldHelper.getTypeForVectorField(field) - ).collect(Collectors.toList()); - - return String.join(", ", columns); - } - - /** - * Returns key column names and type for key column for CREATE TABLE statement - * @param field the key field. - * @return column name and type of the key field for CREATE TABLE statement. - */ - static String getKeyColumnNameAndType(VectorStoreRecordKeyField field) { - return validateObjectNaming(field.getEffectiveStorageName()) + " " + supportedKeyTypes.get(field.getFieldType()); - } - - - /** - * Generates the index name given the field name. by suffixing "_VECTOR_INDEX" to the field name. - * @param effectiveStorageName the field name. - * @return the index name. - */ - static String getIndexName(String effectiveStorageName) { - return effectiveStorageName + VECTOR_INDEX_SUFFIX; - } - - /** - * Gets the type of the vector given the field definition. This method is not needed if only - * - * @param field the vector field definition. - * @return returns the type of vector for the given field type. - */ - private static String getTypeForVectorField(VectorStoreRecordVectorField field) { - String dimension = field.getDimensions() > 0 ? String.valueOf(field.getDimensions()) : "*"; - return String.format(supportedVectorTypes.get(field.getFieldType()), dimension); - } - - /** - * Gets the function that allows to return the function that converts the JSON value to the - * data type. - * @param jdbcType The JDBC type. - * @return the function that allows to return the function that converts the JSON value to the - * data type. - */ - private static String getFunctionForType(String jdbcType) { - switch (jdbcType) { - case OracleDataTypesMapping.BOOLEAN: - return "boolean()"; - case OracleDataTypesMapping.BYTE: - case OracleDataTypesMapping.SHORT: - case OracleDataTypesMapping.INTEGER: - case OracleDataTypesMapping.LONG: - case OracleDataTypesMapping.FLOAT: - case OracleDataTypesMapping.DOUBLE: - case OracleDataTypesMapping.DECIMAL: - return "numberOnly()"; - case OracleDataTypesMapping.OFFSET_DATE_TIME: - return "timestamp()"; - default: - return "string()"; - } - } - - - /** - * Validates an SQL identifier. - * - * @param identifier the identifier - * @return the identifier if it is valid - * @throws SKException if the identifier is invalid - */ - static String validateObjectNaming(String identifier) { - if (identifier.matches(OBJECT_NAMING_REGEXP)) { - return identifier; - } - throw new SKException("Invalid SQL identifier: " + identifier); - } - -} diff --git a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreQueryProvider.java b/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreQueryProvider.java deleted file mode 100644 index e3fa157b9..000000000 --- a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreQueryProvider.java +++ /dev/null @@ -1,866 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigDecimal; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.GuardedBy; -import javax.sql.DataSource; -import oracle.jdbc.OraclePreparedStatement; -import oracle.jdbc.OracleStatement; -import oracle.jdbc.OracleTypes; -import oracle.jdbc.provider.oson.OsonFactory; -import oracle.sql.TIMESTAMPTZ; - -/** - * JDBC Vector Store for the Oracle Database - */ -public class OracleVectorStoreQueryProvider extends JDBCVectorStoreQueryProvider { - - // This could be removed if super.collectionTable made protected - private final String collectionsTable; - - // This could be common to all query providers - private final ObjectMapper objectMapper; - - /** - * Lock used to ensure that only one thread can create a collection at a time. - */ - private static final ReentrantLock dbCreationLock = new ReentrantLock(); - - /** - * The logger - */ - private static final Logger LOGGER = Logger.getLogger(OracleVectorStoreQueryProvider.class.getName()); - - public enum StringTypeMapping { - /** - * Maps String to CLOB - */ - USE_CLOB, - /** - * Maps String to VARCHAR2(4000) - */ - USE_VARCHAR - } - - /** - * Create an instance of OracleVectorStoreQueryProvider. - * - * @param dataSource the datasource - * @param collectionsTable the collections table name - * @param prefixForCollectionTables the prefix for the collection table name - * @param defaultVarcharSize the size of VARCHAR columns - * @param stringTypeMapping the storage type of string columns (VARCHAR or CLOB) - * @param objectMapper the object mapper. - */ - private OracleVectorStoreQueryProvider( - @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables, - int defaultVarcharSize, - @Nonnull StringTypeMapping stringTypeMapping, - ObjectMapper objectMapper) { - super( - dataSource, - collectionsTable, - prefixForCollectionTables, - OracleVectorStoreFieldHelper.getSupportedKeyTypes(), - OracleVectorStoreFieldHelper.getSupportedDataTypes(stringTypeMapping, defaultVarcharSize), - OracleVectorStoreFieldHelper.getSupportedVectorTypes()); - this.collectionsTable = collectionsTable; - this.objectMapper = objectMapper; - // The JavaTimeModule must be registered to handle OffsetDateTime. To make sure that it is - // registered enable the feature IGNORE_DUPLICATE_MODULE_REGISTRATIONS and register the - // module. - this.objectMapper.enable(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS); - this.objectMapper.registerModule(new JavaTimeModule()); - } - - /** - *

- * Creates a collection with the given name and record definition. - *

- * A collection is represented as a table in an Oracle DB containing columns - * that match the record definition. The table name is the name of the collection - * prefixed by the provided collection prefix. If no prefix was provided the default - * prefix will be used. - *

- * @param collectionName the name of the collection - * @param recordDefinition the record definition - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - @GuardedBy("dbCreationLock") - public void createCollection(String collectionName, - VectorStoreRecordDefinition recordDefinition) { - - dbCreationLock.lock(); - try { - - List vectorFields = recordDefinition.getVectorFields(); - String createStorageTable = formatQuery("CREATE TABLE IF NOT EXISTS %s (" - + "%s PRIMARY KEY, " - + "%s, " - + "%s)", - getCollectionTableName(collectionName), - OracleVectorStoreFieldHelper.getKeyColumnNameAndType(recordDefinition.getKeyField()), - getColumnNamesAndTypes(new ArrayList<>(recordDefinition.getDataFields()), - getSupportedDataTypes()), - OracleVectorStoreFieldHelper.getVectorColumnNamesAndTypes( - new ArrayList<>(vectorFields))); - - String insertCollectionQuery = this.getInsertCollectionQuery(collectionsTable); - - try (Connection connection = dataSource.getConnection()) { - // set auto commit of, either all statements should be executed or none - connection.setAutoCommit(false); - try (Statement statement = connection.createStatement()) { - // Create table - statement.addBatch(createStorageTable); - LOGGER.finest("Creating collection " + collectionName + - " using statement: " + createStorageTable); - - // Index filterable data columns - for (VectorStoreRecordDataField dataField : recordDefinition.getDataFields()) { - if (dataField.isFilterable()) { - String dataFieldIndex = OracleVectorStoreFieldHelper.createIndexForDataField( - getCollectionTableName(collectionName), dataField, supportedDataTypes); - statement.addBatch(dataFieldIndex); - LOGGER.finest("Creating index on column " - + dataField.getEffectiveStorageName() + " using the statement: " - + dataFieldIndex); - } - } - - // Create index for vectorFields - for (VectorStoreRecordVectorField vectorField : vectorFields) { - String createVectorIndex = OracleVectorStoreFieldHelper.getCreateVectorIndexStatement( - vectorField, getCollectionTableName(collectionName)); - if (createVectorIndex != null) { - statement.addBatch(createVectorIndex); - LOGGER.finest("Creating index on vector column " - + vectorField.getEffectiveStorageName() + " using the statement: " - + createVectorIndex); - - } - } - statement.executeBatch(); - - // Insert the collection to the store (collections table) using MERGE statement - try (PreparedStatement insert = connection.prepareStatement( - insertCollectionQuery)) { - insert.setString(1, collectionName); - insert.execute(); - LOGGER.finest("Inserting collection to store using statement: " + - insertCollectionQuery); - } - - connection.commit(); - } catch (SQLException e) { - connection.rollback(); - throw new SKException("Failed to create collection", e); - } - } catch (SQLException e) { - throw new SKException("Failed to create collection", e); - } - } finally { - dbCreationLock.unlock(); - } - } - - /** - *

- * Inserts or updates record of a collection given the collection name, the records, the record - * definition and the upsert options. - *

- * @Note At the moment {@link UpsertRecordOptions} is an empty class. No options are available. - *

- * - * @param collectionName the collection name - * @param records the records to update or insert - * @param recordDefinition the record definition - * @param options the options - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - public void upsertRecords(String collectionName, - List records, - VectorStoreRecordDefinition recordDefinition, - UpsertRecordOptions options) { - - final String NEW_VALUE = "new"; - final String EXISTING_VALUE = "existing"; - - // generate the comma separated list of new fields - // Ex.: new.field1, new.field2 ... new.fieldn - String insertNewFieldList = recordDefinition.getAllFields().stream() - .map(f -> NEW_VALUE + "." + f.getEffectiveStorageName()) - .collect(Collectors.joining(", ")); - - // generate the comma separated list of existing fields - // Ex.: existing.field1, existing.field2 ... existing.fieldn - String insertExistingFieldList = recordDefinition.getAllFields().stream() - .map(f -> EXISTING_VALUE + "." + f.getEffectiveStorageName()) - .collect(Collectors.joining(", ")); - - // generate the comma separated list for setting new values on fields - // Ex.: new.field1 = existing.field1, new.field2 = existing.field2 ... new.fieldn = existing.fieldn - String updateFieldList = recordDefinition.getAllFields().stream() - .filter(f -> f != recordDefinition.getKeyField()) - .map(f -> EXISTING_VALUE + "." + f.getEffectiveStorageName() + " = " + NEW_VALUE + "." + f.getEffectiveStorageName()) - .collect(Collectors.joining(", ")); - - // generate the comma separated list of placeholders "?" for each field - // Ex.: ? field1, ? field2 ... ? fieldn - String namedPlaceholders = recordDefinition.getAllFields().stream().map(f -> "? " + f.getEffectiveStorageName()) - .collect(Collectors.joining(", ")); - - // Generate the MERGE statement to perform the upsert. - String upsertStatement = formatQuery("MERGE INTO %s existing "+ - "USING (SELECT %s FROM DUAL) new ON (existing.%s = new.%s) " + - "WHEN MATCHED THEN UPDATE SET %s " + - "WHEN NOT MATCHED THEN INSERT (%s) VALUES (%s)", - getCollectionTableName(collectionName), - namedPlaceholders, - getKeyColumnName(recordDefinition.getKeyField()), - getKeyColumnName(recordDefinition.getKeyField()), - updateFieldList, - insertExistingFieldList, - insertNewFieldList); - - LOGGER.finest("Generated upsert statement: " + upsertStatement); - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(upsertStatement)) { - // Loop through records, set values and add values to batch - for (Object record : records) { - setUpsertStatementValues(statement, record, recordDefinition.getAllFields()); - statement.addBatch(); - } - - // Execute the upsert statement - statement.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to upsert records", e); - } - } - - /** - * Generates the MERGE statement to add the given collection to the store. - * - * @param collectionsTable the name of the DB table containing all collections. - * @return a SQL statement that inserts a collection to the store if it does not exist. - */ - @Override - protected String getInsertCollectionQuery(String collectionsTable) { - return formatQuery( - "MERGE INTO %s existing "+ - "USING (SELECT ? AS collectionId FROM DUAL) new ON (existing.collectionId = new.collectionId) " + - "WHEN NOT MATCHED THEN INSERT (existing.collectionId) VALUES (new.collectionId)", - collectionsTable); - } - - /** - * The {@link OracleVectorStoreQueryProvider#upsertRecords(String, List, VectorStoreRecordDefinition, UpsertRecordOptions)} - * method adds a placeholder for each field. This method sets the value of each field on the - * MERGE statement with the value of the record. The placeholder and values are set in the order - * of the fields in the list. - * - * @param upsertStatement the MERGE statement - * @param record the record containing the values - * @param fields the list of fields. - */ - private void setUpsertStatementValues(PreparedStatement upsertStatement, Object record, - List fields) { - - // use the object mapper to convert the record to an equivalent tree mode JsonNode value, - // this allows to retrieve the values using the effective storage name of the fields and - // avoids the use of introspection. - JsonNode jsonNode = objectMapper.valueToTree(record); - - for (int i = 0; i < fields.size(); ++i) { - VectorStoreRecordField field = fields.get(i); - try { - - JsonNode valueNode = jsonNode.get(field.getEffectiveStorageName()); - - // Some field types require special treatment to convert the java type to the - // DB type - if (field instanceof VectorStoreRecordVectorField) { - // If the vector field is not set as a string convert to an array of floats - // and set the value - if (!field.getFieldType().equals(String.class)) { - if (valueNode != null && !valueNode.isNull() && valueNode.isArray()) { - final float[] values = new float[valueNode.size()]; - for (int j = 0; j < ((ArrayNode)valueNode).size(); j++) { - values[j] = ((ArrayNode)valueNode).get(j).floatValue(); - } - upsertStatement.setObject(i + 1, values, OracleTypes.VECTOR_FLOAT32); - } else { - upsertStatement.setNull(i + 1, OracleTypes.VECTOR_FLOAT32); - } - continue; - } - } else if (field instanceof VectorStoreRecordDataField) { - // Lists are stored as JSON objects, write the list using the JDBC OSON - // extensions. - if (field.getFieldType().equals(List.class)) { - JsonFactory osonFactory = new OsonFactory(); - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - try (JsonGenerator osonGen = osonFactory.createGenerator(out)) { - objectMapper.writeValue(osonGen, valueNode); - } - upsertStatement.setBytes(i + 1, out.toByteArray()); - } catch (IOException ioEx) { - throw new SKException("Failed to convert list to JSON value", ioEx); - } - continue; - } - // Convert UUID to string before setting the value. - if (field.getFieldType().equals(UUID.class)) { - upsertStatement.setObject(i + 1, valueNode.isNull() ? null : valueNode.asText()); - continue; - } - // Convert value node (its representations depends on Jackson JSON features) - // to OffsetDateTime before setting the value. - if (field.getFieldType().equals(OffsetDateTime.class)) { - if (valueNode == null || valueNode.isNull()) { - upsertStatement.setNull(i + 1, OracleTypes.TIMESTAMPTZ); - } else { - OffsetDateTime offsetDateTime = (OffsetDateTime) objectMapper.convertValue(valueNode, field.getFieldType()); - upsertStatement.setObject(i + 1, offsetDateTime); - } - continue; - } - } - - // For all other field type use setObject with the field value - upsertStatement.setObject(i + 1, - objectMapper.convertValue(valueNode,field.getFieldType())); - } catch (SQLException e) { - throw new SKException(e); - } - } - } - - /** - *

- * Executes a vector search query, using the search options and returns the results. The results - * are mapped to the specified record type using the provided mapper. The query is executed - * against the specified collection. - *

- * - *

- * @param collectionName the collection name - * @param vector the vector to search with - * @param options the search options - * @param recordDefinition the record definition - * @param mapper the mapper, responsible for mapping the result set to the record - * type. - * @return the search results - * @param the record type - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") - public VectorSearchResults search(String collectionName, List vector, - VectorSearchOptions options, VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper) { - - - if (vector != null && recordDefinition.getVectorFields().isEmpty()) { - throw new SKException("Record definition must contain at least one vector field" - + " to perform a vector search"); - } - - // Gets the search vector field and its distance function. If not vector field was provided, - // use the first one - VectorStoreRecordVectorField vectorField = null; - if (vector != null) { - vectorField = getVectorFieldByName(recordDefinition, options.getVectorFieldName()); - } - - - - // get list of fields that should be returned by the query - List fields = (options.isIncludeVectors()) - ? recordDefinition.getAllFields() - : recordDefinition.getNonVectorFields(); - - // get search filters and get the list of parameters for the filters - String filter = getFilter(options.getVectorSearchFilter(), recordDefinition); - List parameters = getFilterParameters(options.getVectorSearchFilter()); - - // generate SQL statement - String selectQuery = "SELECT " - + (vector == null ? "0 as distance, " : - formatQuery("VECTOR_DISTANCE(%s, ?, %s) distance, ", - OracleVectorStoreFieldHelper.validateObjectNaming(vectorField.getEffectiveStorageName()), - toOracleDistanceFunction(vectorField.getDistanceFunction()))) - + getQueryColumnsFromFields(fields) - + " FROM " + getCollectionTableName(collectionName) - + (filter != null && !filter.isEmpty() ? " WHERE " + filter : "") - + " ORDER BY distance" - + (options.getSkip() > 0 ? " OFFSET " + options.getSkip() + " ROWS" : "") - + (options.getTop() > 0 ? " FETCH " + (options.getSkip() > 0 ? "NEXT " : "FIRST ") + options.getTop() + " ROWS ONLY" : ""); - LOGGER.finest("Search using statement: " + selectQuery); - - // Execute the statement - List> records = new ArrayList<>(); - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(selectQuery)) { - // set parameters from filters - int parameterIndex = 1; - // if a vector was provided for similarity search set the value of the vector - if (vector != null) { - float[] arrayVector = new float[vector.size()]; - for (int i = 0; i < vector.size(); i++){ - arrayVector[i] = vector.get(i).floatValue(); - } - statement.setObject(parameterIndex++, arrayVector, OracleTypes.VECTOR_FLOAT32); - } - // set all parameters. - for (Object parameter : parameters) { - if (parameter != null) { - setSearchParameter(statement, parameterIndex++, parameter.getClass(), parameter); - } - } - - // Calls to defineColumnType reduce the number of network requests. When Oracle JDBC knows that it is - // fetching VECTOR, CLOB, and/or JSON columns, the first request it sends to the database can include a LOB - // prefetch size (VECTOR and JSON are value-based-lobs). If defineColumnType is not called, then JDBC needs - // to send an additional request with the LOB prefetch size, after the first request has the database - // respond with the column data types. To request all data, the prefetch size is Integer.MAX_VALUE. - OracleStatement oracleStatement = statement.unwrap(OracleStatement.class); - int columnIndex = 1; - // define distance column as double - defineDataColumnType(columnIndex++, oracleStatement, Double.class); - // define columns for returned fields - for (VectorStoreRecordField field : fields) { - if (!(field instanceof VectorStoreRecordVectorField)) - defineDataColumnType(columnIndex++, oracleStatement, field.getFieldType()); - else - oracleStatement.defineColumnType(columnIndex++, OracleTypes.VECTOR_FLOAT32, - Integer.MAX_VALUE); - } - oracleStatement.setLobPrefetchSize(Integer.MAX_VALUE); // Workaround for Oracle JDBC bug 37030121 - - // Execute the statement and get the results - try (ResultSet rs = statement.executeQuery()) { - GetRecordOptions getRecordOptions = new GetRecordOptions(options.isIncludeVectors()); - while (rs.next()) { - // Cosine distance function. 1 - cosine similarity. - double score = Math.abs(rs.getDouble("distance")); - if (vector != null && vectorField.getDistanceFunction() == DistanceFunction.COSINE_SIMILARITY) { - score = 1d - score; - } - // Use the mapper to convert to result set to records - records.add(new VectorSearchResult<>(mapper.mapStorageModelToRecord(rs, getRecordOptions), score)); - } - } - } catch (SQLException e) { - throw new SKException("Search failed", e); - } - - return new VectorSearchResults<>(records); - } - - private VectorStoreRecordVectorField getVectorFieldByName( - VectorStoreRecordDefinition recordDefinition, - String name) { - VectorStoreRecordField vectorField; - if (name != null) { - vectorField = recordDefinition.getField(name); - if (vectorField == null) { - throw new SKException("Vector field not found in record definition"); - } - if (!(vectorField instanceof VectorStoreRecordVectorField)) { - throw new SKException("Invalid type"); - } - } else { - if (recordDefinition.getVectorFields().isEmpty()) { - throw new SKException("Record definition should contain at least one vector field"); - } - vectorField = recordDefinition.getVectorFields().get(0); - } - return (VectorStoreRecordVectorField)vectorField; - } - - /** - * Sets the parameter value - * @param statement the statement - * @param index the parameter index - * @param type the parameter type - * @param value the value - */ - private void setSearchParameter(PreparedStatement statement, int index, Class type, Object value) { - - try { - // Use JSON string to set lists - if (List.class.equals(type)) { - statement.setObject(index, objectMapper.writeValueAsString(value)); - return; - } - // convert UUID to string - if (UUID.class.equals(type)) { - statement.setString(index, value.toString()); - return; - } - // convert OffsetDateType to TIMESTAMPTZ - if (OffsetDateTime.class.equals(type)) { - if (value == null) { - statement.setNull(index, OracleTypes.TIMESTAMPTZ); - } else { - OffsetDateTime offsetDateTime = (OffsetDateTime) value; - ((OraclePreparedStatement) statement).setTIMESTAMPTZ(index, - TIMESTAMPTZ.of(offsetDateTime)); - } - return; - } - // use setBigDecimal to set BigDecimal value - if (BigDecimal.class.equals(type)) { - if (value == null) { - statement.setNull(index, OracleTypes.DECIMAL); - } else { - BigDecimal bigDecimal = (BigDecimal) value; - ((OraclePreparedStatement) statement).setBigDecimal(index, - bigDecimal); - } - return; - } - - // for all other types set object with the given value - statement.setObject(index, value); - - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - - /** - * Defines the type that will be used to retrieve data from a given database table column. - * @param columnIndex the index of the column - * @param statement the statement - * @param fieldType the java field type - * @throws SQLException if an error occurs while defining the column type - */ - private void defineDataColumnType(int columnIndex, OracleStatement statement, Class fieldType) throws SQLException { - // switch between supported classes and define the column type on the statement - switch (supportedDataTypes.get(fieldType)) { - case OracleDataTypesMapping.STRING_CLOB: - statement.defineColumnType(columnIndex, OracleTypes.CLOB, Integer.MAX_VALUE); - break; - case OracleDataTypesMapping.BYTE: - statement.defineColumnType(columnIndex, OracleTypes.NUMBER); - break; - case OracleDataTypesMapping.SHORT: - statement.defineColumnType(columnIndex, OracleTypes.NUMBER); - break; - case OracleDataTypesMapping.INTEGER: - statement.defineColumnType(columnIndex, OracleTypes.INTEGER); - break; - case OracleDataTypesMapping.LONG: - statement.defineColumnType(columnIndex, OracleTypes.BIGINT); - break; - case OracleDataTypesMapping.FLOAT: - statement.defineColumnType(columnIndex, OracleTypes.BINARY_FLOAT); - break; - case OracleDataTypesMapping.DOUBLE: - statement.defineColumnType(columnIndex, OracleTypes.BINARY_DOUBLE); - break; - case OracleDataTypesMapping.DECIMAL: - statement.defineColumnType(columnIndex, OracleTypes.BINARY_DOUBLE); - break; - case OracleDataTypesMapping.BOOLEAN: - statement.defineColumnType(columnIndex, OracleTypes.BOOLEAN); - break; - case OracleDataTypesMapping.OFFSET_DATE_TIME: - statement.defineColumnType(columnIndex, OracleTypes.TIMESTAMPTZ); - break; - case OracleDataTypesMapping.JSON: - statement.defineColumnType(columnIndex, OracleTypes.JSON, Integer.MAX_VALUE); - break; - case OracleDataTypesMapping.BYTE_ARRAY: - statement.defineColumnType(columnIndex, OracleTypes.RAW); - default: - statement.defineColumnType(columnIndex, OracleTypes.VARCHAR); - } - } - - /** - * Converts a {@link DistanceFunction} to the equivalent Oracle distance function. - * @param distanceFunction the distance function - * @return the Oracle distance function - */ - private String toOracleDistanceFunction(DistanceFunction distanceFunction) { - switch (distanceFunction) { - case DOT_PRODUCT: - return "DOT"; - case COSINE_SIMILARITY: - case COSINE_DISTANCE: - return "COSINE"; - case EUCLIDEAN_DISTANCE: - return "EUCLIDEAN"; - default: - return "COSINE"; - } - } - - /** - * Gets the filter parameters for the given vector search filter to associate with the filter - * string generated by the getFilter method. - * - * @param filter The filter to get the filter parameters for. - * @return The filter parameters. - */ - @Override - public List getFilterParameters(VectorSearchFilter filter) { - // TODO: this method should be protected, not public - if (filter == null - || filter.getFilterClauses().isEmpty()) { - return Collections.emptyList(); - } - - return filter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - return equalToFilterClause.getValue(); - } else if (filterClause instanceof AnyTagEqualToFilterClause) { - AnyTagEqualToFilterClause anyTagEqualToFilterClause = (AnyTagEqualToFilterClause) filterClause; - return anyTagEqualToFilterClause.getValue(); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.toList()); - } - - /** - * Gets the filter clause for an equal to filter - * @param filterClause The equal to filter clause to get the filter string for. - * @return the filter clause - */ - @Override - public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(filterClause.getFieldName()); - Object value = filterClause.getValue(); - - if (value == null) { - return String.format("%s is NULL", fieldName); - } else { - return String.format("%s = ?", fieldName); - } - } - - /** - * Gets the filter clause for an any tag equal to filter - * @param filterClause The any tag equal to filter clause to get the filter string for. - * @return the filter clause - */ - @Override - public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - String fieldName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(filterClause.getFieldName()); - - return String.format("JSON_EXISTS(%s, '$[*]?(@ == $v_%s)' PASSING ? AS \"v_%s\")", - fieldName, fieldName, fieldName); - } - - /** - * Gets the mapper used to map a ResultSet to records - * @param recordClass the record class - * @param vectorStoreRecordDefinition the record definition - * @return the vector store record mapper - * @param the type of the records - */ - @Override - public VectorStoreRecordMapper getVectorStoreRecordMapper( - Class recordClass, - VectorStoreRecordDefinition vectorStoreRecordDefinition) { - return OracleVectorStoreRecordMapper.builder() - .withRecordClass(recordClass) - .withVectorStoreRecordDefinition(vectorStoreRecordDefinition) - .withSupportedDataTypesMapping(getSupportedDataTypes()) - .build(); - } - - /** - * Gets a builder that allows to build an OracleVectorStoreQueryProvider - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * OracleVectorStoreQueryProvider builder. - */ - public static class Builder - extends JDBCVectorStoreQueryProvider.Builder { - - /** - * The data source - */ - private DataSource dataSource; - - /** - * The collections table - */ - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - - /** - * The prefix for collection table names - */ - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - - /** - * The object mapper - */ - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * The string type mapping choice - */ - private StringTypeMapping stringTypeMapping = StringTypeMapping.USE_VARCHAR; - - /** - * The size of varchar columns - */ - private int defaultVarcharSize = 2000; - - - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * @param collectionsTable the collections table name - * @return the builder - */ - public Builder withCollectionsTable(String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Sets the object mapper used to map records to and from results - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper( - ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Sets the desired String type mapping. - * @param stringTypeMapping the desired String type mapping. The default value is - * {@link StringTypeMapping#USE_VARCHAR} - * @return the builder - */ - public Builder withStringTypeMapping (StringTypeMapping stringTypeMapping) { - this.stringTypeMapping = stringTypeMapping; - return this; - } - - /** - * Sets the default size of the VARHCHAR fields. - * @param defaultVarcharSize the default size of the VARHCHAR fields. By default, the size - * is 2000. - * @return then builder - */ - public Builder withDefaultVarcharSize (int defaultVarcharSize) { - this.defaultVarcharSize = defaultVarcharSize; - return this; - } - - /** - * Builds and Oracle vector store query provider. - * @return the query provider - */ - @Override - public OracleVectorStoreQueryProvider build() { - return new OracleVectorStoreQueryProvider(dataSource, collectionsTable, - prefixForCollectionTables, defaultVarcharSize, stringTypeMapping, objectMapper); - } - } -} - diff --git a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordMapper.java b/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordMapper.java deleted file mode 100644 index c75eb6631..000000000 --- a/data/semantickernel-data-oracle/src/main/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordMapper.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import oracle.jdbc.provider.oson.OsonModule; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Map; -import java.util.HashMap; -import java.util.UUID; -import java.util.function.BiFunction; - -/** - * Maps a Oracle result set to a record. - * - * @param the record type - */ -public class OracleVectorStoreRecordMapper - extends VectorStoreRecordMapper { - - /** - * Constructs a new instance of the VectorStoreRecordMapper. - * - * @param storageModelToRecordMapper the function to convert a storage model to a record - */ - protected OracleVectorStoreRecordMapper( - BiFunction storageModelToRecordMapper) { - super(null, storageModelToRecordMapper); - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Operation not supported. - */ - @Override - public ResultSet mapRecordToStorageModel(Record record) { - throw new UnsupportedOperationException("Not implemented"); - } - - /** - * Builder for {@link OracleVectorStoreRecordMapper}. - * - * @param the record type - */ - public static class Builder - implements SemanticKernelBuilder> { - private Class recordClass; - private VectorStoreRecordDefinition vectorStoreRecordDefinition; - private Map, String> supportedDataTypesMapping; - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record definition. - * - * @param vectorStoreRecordDefinition the vector store record definition - * @return the builder - */ - public Builder withVectorStoreRecordDefinition( - VectorStoreRecordDefinition vectorStoreRecordDefinition) { - this.vectorStoreRecordDefinition = vectorStoreRecordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Sets the Map of supported data types and their database representation - * - * @param supportedDataTypesMapping the Map of supported data types and their - * database representation - * @return the builder - */ - public Builder withSupportedDataTypesMapping( - Map, String> supportedDataTypesMapping) { - this.supportedDataTypesMapping = new HashMap<>(supportedDataTypesMapping); - return this; - } - - /** - * Builds the {@link OracleVectorStoreRecordMapper}. - * - * @return the {@link OracleVectorStoreRecordMapper} - */ - public OracleVectorStoreRecordMapper build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - if (vectorStoreRecordDefinition == null) { - throw new SKException("vectorStoreRecordDefinition is required"); - } - - return new OracleVectorStoreRecordMapper<>( - (resultSet, options) -> { - return mapResultSetToRecord(resultSet, options); - }); - } - - private Record mapResultSetToRecord(ResultSet resultSet, GetRecordOptions options) { - try { - objectMapper.registerModule(new OsonModule()); - // Create an ObjectNode to hold the values - ObjectNode objectNode = objectMapper.createObjectNode(); - - // Read non vector fields - for (VectorStoreRecordField field : vectorStoreRecordDefinition.getNonVectorFields()) { - Class fieldType = field.getFieldType(); - - Object value; - switch (supportedDataTypesMapping.get(fieldType)) { - case OracleDataTypesMapping.STRING_CLOB: - value = resultSet.getString(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.BYTE: - value = resultSet.getByte(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.SHORT: - value = resultSet.getShort(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.INTEGER: - value = resultSet.getInt(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.LONG: - value = resultSet.getLong(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.FLOAT: - value = resultSet.getFloat(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.DOUBLE: - value = resultSet.getDouble(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.DECIMAL: - value = resultSet.getBigDecimal(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.BOOLEAN: - value = resultSet.getBoolean(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.OFFSET_DATE_TIME: - value = resultSet.getObject(field.getEffectiveStorageName(), fieldType); - break; - case OracleDataTypesMapping.BYTE_ARRAY: - value = resultSet.getBytes(field.getEffectiveStorageName()); - break; - case OracleDataTypesMapping.UUID: - String uuidValue = resultSet.getString(field.getEffectiveStorageName()); - value = uuidValue == null ? null : UUID.fromString(uuidValue); - break; - case OracleDataTypesMapping.JSON: - value = resultSet.getObject(field.getEffectiveStorageName(), fieldType); - break; - default: - value = resultSet.getString(field.getEffectiveStorageName()); - } - // Result set getter method sometimes returns a default value when NULL, - // set value to null in that case. - if (resultSet.wasNull()) { - value = null; - } - - JsonNode genericNode = objectMapper.valueToTree(value); - - objectNode.set(field.getEffectiveStorageName(), genericNode); - } - if (options != null && options.isIncludeVectors()) { - for (VectorStoreRecordVectorField field : vectorStoreRecordDefinition.getVectorFields()) { - - // String vector - if (field.getFieldType().equals(String.class)) { - float[] arr = resultSet.getObject(field.getEffectiveStorageName(), float[].class); - String str = (arr == null) - ? null - : objectMapper.writeValueAsString(arr); - objectNode.put(field.getEffectiveStorageName(), str); - continue; - } - - Object value = resultSet.getObject(field.getEffectiveStorageName(), float[].class); - JsonNode genericNode = objectMapper.valueToTree(value); - objectNode.set(field.getEffectiveStorageName(), genericNode); - } - } else { - for (VectorStoreRecordVectorField field : vectorStoreRecordDefinition.getVectorFields()) { - JsonNode genericNode = objectMapper.valueToTree(null); - objectNode.set(field.getEffectiveStorageName(), genericNode); - } - } - - // Deserialize the object node to the record class - return objectMapper.convertValue(objectNode, recordClass); - } catch (SQLException e) { - throw new SKException( - "Failure to serialize object, by default the JDBC connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllBoxedTypes.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllBoxedTypes.java deleted file mode 100644 index 14b96c142..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllBoxedTypes.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import java.math.BigDecimal; -import java.time.OffsetDateTime; -import java.util.List; -import java.util.UUID; - -public class ClassWithAllBoxedTypes { - - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final Boolean booleanValue; - - @VectorStoreRecordData(isFilterable = true) - private final Byte byteValue; - - @VectorStoreRecordData(isFilterable = true) - private final Short shortValue; - - @VectorStoreRecordData(isFilterable = true) - private final Integer integerValue; - - @VectorStoreRecordData(isFilterable = true) - private final Long longValue; - - @VectorStoreRecordData(isFilterable = true) - private final Float floatValue; - - @VectorStoreRecordData(isFilterable = true) - private final Double doubleValue; - - @VectorStoreRecordData(isFilterable = true) - private final BigDecimal decimalValue; - - @VectorStoreRecordData(isFilterable = true) - private final OffsetDateTime offsetDateTimeValue; - - @VectorStoreRecordData(isFilterable = true) - private final UUID uuidValue; - - @VectorStoreRecordData(isFilterable = true) - private final byte[] byteArrayValue; - - @VectorStoreRecordData(isFilterable = true) - private final List listOfFloatValue; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private final Float[] vectorValue; - - - public ClassWithAllBoxedTypes() { - this(null, false, Byte.MIN_VALUE,Short.MIN_VALUE, 0, 0l, 0f, 0d, null, null, null, null, null, null); - }; - public ClassWithAllBoxedTypes(String id, Boolean booleanValue, Byte byteValue, - Short shortValue, Integer integerValue, Long longValue, Float floatValue, Double doubleValue, - BigDecimal decimalValue, OffsetDateTime offsetDateTimeValue, UUID uuidValue, - byte[] byteArrayValue, List listOfFloatValue, Float[] vectorValue) { - this.id = id; - this.booleanValue = booleanValue; - this.byteValue = byteValue; - this.shortValue = shortValue; - this.integerValue = integerValue; - this.longValue = longValue; - this.floatValue = floatValue; - this.doubleValue = doubleValue; - this.decimalValue = decimalValue; - this.offsetDateTimeValue = offsetDateTimeValue; - this.uuidValue = uuidValue; - this.byteArrayValue = byteArrayValue; - this.listOfFloatValue = listOfFloatValue; - this.vectorValue = vectorValue; - } - - public String getId() { - return id; - } - - public Boolean getBooleanValue() { - return booleanValue; - } - - public Byte getByteValue() { - return byteValue; - } - - public Short getShortValue() { - return shortValue; - } - - public Integer getIntegerValue() { - return integerValue; - } - - public Long getLongValue() { - return longValue; - } - - public Float getFloatValue() { - return floatValue; - } - - public Double getDoubleValue() { - return doubleValue; - } - - - public BigDecimal getDecimalValue() { - return decimalValue; - } - - public OffsetDateTime getOffsetDateTimeValue() { - return offsetDateTimeValue; - } - - public UUID getUuidValue() { - return uuidValue; - } - - public byte[] getByteArrayValue() { - return byteArrayValue; - } - - public List getListOfFloatValue() { - return listOfFloatValue; - } - - public Float[] getVectorValue() { - return vectorValue; - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllPrimitiveTypes.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllPrimitiveTypes.java deleted file mode 100644 index 6a8d76d07..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAllPrimitiveTypes.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import java.math.BigDecimal; -import java.time.OffsetDateTime; -import java.util.List; -import java.util.UUID; - -public class ClassWithAllPrimitiveTypes { - - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final Boolean booleanValue; - - @VectorStoreRecordData(isFilterable = true) - private final byte byteValue; - - @VectorStoreRecordData(isFilterable = true) - private final short shortValue; - - @VectorStoreRecordData(isFilterable = true) - private final int integerValue; - - @VectorStoreRecordData(isFilterable = true) - private final long longValue; - - @VectorStoreRecordData(isFilterable = true) - private final float floatValue; - - @VectorStoreRecordData(isFilterable = true) - private final double doubleValue; - - @VectorStoreRecordData(isFilterable = true) - private final BigDecimal decimalValue; - - @VectorStoreRecordData(isFilterable = true) - private final OffsetDateTime offsetDateTimeValue; - - @VectorStoreRecordData(isFilterable = true) - private final UUID uuidValue; - - @VectorStoreRecordData(isFilterable = true) - private final byte[] byteArrayValue; - - @VectorStoreRecordData(isFilterable = true) - private final List listOfFloatValue; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private final float[] vectorValue; - - - public ClassWithAllPrimitiveTypes() { - this(null, false, Byte.MIN_VALUE,Short.MIN_VALUE, 0, 0l, 0f, 0d, null, null, null, null, null, null); - }; - public ClassWithAllPrimitiveTypes(String id, boolean booleanValue, byte byteValue, - short shortValue, int integerValue, long longValue, float floatValue, double doubleValue, - BigDecimal decimalValue, OffsetDateTime offsetDateTimeValue, UUID uuidValue, - byte[] byteArrayValue, List listOfFloatValue, float[] vectorValue) { - this.id = id; - this.booleanValue = booleanValue; - this.byteValue = byteValue; - this.shortValue = shortValue; - this.integerValue = integerValue; - this.longValue = longValue; - this.floatValue = floatValue; - this.doubleValue = doubleValue; - this.decimalValue = decimalValue; - this.offsetDateTimeValue = offsetDateTimeValue; - this.uuidValue = uuidValue; - this.byteArrayValue = byteArrayValue; - this.listOfFloatValue = listOfFloatValue; - this.vectorValue = vectorValue; - } - - public String getId() { - return id; - } - - public boolean getBooleanValue() { - return booleanValue; - } - - public byte getByteValue() { - return byteValue; - } - - public short getShortValue() { - return shortValue; - } - - public int getIntegerValue() { - return integerValue; - } - - public long getLongValue() { - return longValue; - } - - public float getFloatValue() { - return floatValue; - } - - public double getDoubleValue() { - return doubleValue; - } - - - public BigDecimal getDecimalValue() { - return decimalValue; - } - - public OffsetDateTime getOffsetDateTimeValue() { - return offsetDateTimeValue; - } - - public UUID getUuidValue() { - return uuidValue; - } - - public byte[] getByteArrayValue() { - return byteArrayValue; - } - - public List getListOfFloatValue() { - return listOfFloatValue; - } - - public float[] getVectorValue() { - return vectorValue; - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAnnotatedTypes.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAnnotatedTypes.java deleted file mode 100644 index 75190debf..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/ClassWithAnnotatedTypes.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeInfo.As; - -import java.math.BigDecimal; -import java.time.OffsetDateTime; -import java.util.List; -import java.util.UUID; - -public class ClassWithAnnotatedTypes { - - private final String id; - - @JsonProperty("value_type") - private final String valueType; - - @JsonProperty("value_field") - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.EXTERNAL_PROPERTY , property = "value_type") - @JsonSubTypes({ - @JsonSubTypes.Type(value = String.class, name="string"), - @JsonSubTypes.Type(value = Boolean.class, name="boolean"), - @JsonSubTypes.Type(value = Byte.class, name="byte"), - @JsonSubTypes.Type(value = Short.class, name="short"), - @JsonSubTypes.Type(value = Integer.class, name="integer"), - @JsonSubTypes.Type(value = Long.class, name="long"), - @JsonSubTypes.Type(value = Float.class, name="float"), - @JsonSubTypes.Type(value = Double.class, name="double"), - @JsonSubTypes.Type(value = BigDecimal.class, name="decimal"), - @JsonSubTypes.Type(value = OffsetDateTime.class, name="timestamp"), - @JsonSubTypes.Type(value = UUID.class, name="uuid"), - @JsonSubTypes.Type(value = byte[].class, name="byte_array"), - @JsonSubTypes.Type(value = List.class, name="json") - }) - private Object value; - - private final Float[] vectorValue; - - - public ClassWithAnnotatedTypes() { - this(null, null, null, null); - }; - public ClassWithAnnotatedTypes(String id, String valueType, Object value, Float[] vectorValue) { - this.id = id; - this.valueType = valueType; - this.value = value; - this.vectorValue = vectorValue; - } - - public String getId() { - return id; - } - - public String getValueType() { return valueType; } - - public Object getValue() { - return value; - } - - public Float[] getVectorValue() { - return vectorValue; - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java deleted file mode 100644 index 0f93ff7f5..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java +++ /dev/null @@ -1,125 +0,0 @@ - -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING; -import static com.fasterxml.jackson.annotation.JsonCreator.Mode.PROPERTIES; - -public class Hotel { - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final String name; - - @VectorStoreRecordData - private final int code; - - @VectorStoreRecordData - private final double price; - - @VectorStoreRecordData(isFilterable = true) - private final List tags; - - @JsonProperty("summary") - @VectorStoreRecordData( isFilterable = true, isFullTextSearchable = true ) - private final String description; - - @JsonProperty("summaryEmbedding1") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.EUCLIDEAN_DISTANCE, indexKind = IndexKind.IVFFLAT) - private final List euclidean; - - @JsonProperty("summaryEmbedding2") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.HNSW) - private final float[] cosineDistance; - - @JsonProperty("summaryEmbedding3") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_SIMILARITY, indexKind = IndexKind.IVFFLAT) - private final float[] cosineSimilarity; - - @JsonProperty("summaryEmbedding4") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.DOT_PRODUCT, indexKind = IndexKind.IVFFLAT) - private final Float[] dotProduct; - @VectorStoreRecordData - private double rating; - - @JsonCreator(mode = DELEGATING) - public Hotel() { - this(null, null, 0, 0d, null, null, null, null, null, null, 0.0); - } - - @JsonCreator(mode = PROPERTIES) - protected Hotel( - @JsonProperty("id") String id, - @JsonProperty("name") String name, - @JsonProperty("code") int code, - @JsonProperty("price") double price, - @JsonProperty("tags") List tags, - @JsonProperty("summary") String description, - @JsonProperty("summaryEmbedding1") List euclidean, - @JsonProperty("summaryEmbedding2") float[] cosineDistance, - @JsonProperty("summaryEmbedding3") float[] cosineSimilarity, - @JsonProperty("summaryEmbedding4") Float[] dotProduct, - @JsonProperty("rating") double rating) { - this.id = id; - this.name = name; - this.code = code; - this.price = price; - this.tags = tags; - this.description = description; - this.euclidean = euclidean; - this.cosineDistance = cosineDistance; - this.cosineSimilarity = cosineSimilarity; - this.dotProduct = dotProduct; - this.rating = rating; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public int getCode() { - return code; - } - - public double getPrice() { return price; } - - public List getTags() { return tags; } - - public String getDescription() { - return description; - } - - public List getEuclidean() { - return euclidean; - } - - public float[] getCosineDistance() { - return cosineDistance; - } - - public Float[] getDotProduct() { - return dotProduct; - } - - public double getRating() { - return rating; - } - - public void setRating(double rating) { - this.rating = rating; - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleCommonVectorStoreRecordCollectionTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleCommonVectorStoreRecordCollectionTest.java deleted file mode 100644 index ce260c77e..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleCommonVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import oracle.jdbc.OracleConnection; -import oracle.jdbc.datasource.impl.OracleDataSource; -import org.testcontainers.oracle.OracleContainer; -import org.testcontainers.utility.MountableFile; -import java.sql.SQLException; -import java.time.Duration; - -public class OracleCommonVectorStoreRecordCollectionTest { - - protected static final String ORACLE_IMAGE_NAME = "gvenzl/oracle-free:23.7-slim-faststart"; - protected static final OracleDataSource DATA_SOURCE; - protected static final OracleDataSource SYSDBA_DATA_SOURCE; - - static { - - try { - DATA_SOURCE = new oracle.jdbc.datasource.impl.OracleDataSource(); - SYSDBA_DATA_SOURCE = new oracle.jdbc.datasource.impl.OracleDataSource(); - String urlFromEnv = System.getenv("ORACLE_JDBC_URL"); - - if (urlFromEnv == null) { - // The Ryuk component is relied upon to stop this container. - OracleContainer oracleContainer = new OracleContainer(ORACLE_IMAGE_NAME) - .withCopyFileToContainer(MountableFile.forClasspathResource("/initialize.sql"), - "/container-entrypoint-initdb.d/initialize.sql") - .withStartupTimeout(Duration.ofSeconds(600)) - .withConnectTimeoutSeconds(600) - .withDatabaseName("pdb1") - .withUsername("testuser") - .withPassword("testpwd"); - oracleContainer.start(); - - initDataSource( - DATA_SOURCE, - oracleContainer.getJdbcUrl(), - oracleContainer.getUsername(), - oracleContainer.getPassword()); - initDataSource(SYSDBA_DATA_SOURCE, oracleContainer.getJdbcUrl(), "sys", oracleContainer.getPassword()); - } else { - initDataSource( - DATA_SOURCE, - urlFromEnv, - System.getenv("ORACLE_JDBC_USER"), - System.getenv("ORACLE_JDBC_PASSWORD")); - initDataSource( - SYSDBA_DATA_SOURCE, - urlFromEnv, - System.getenv("ORACLE_JDBC_USER"), - System.getenv("ORACLE_JDBC_PASSWORD")); - } - SYSDBA_DATA_SOURCE.setConnectionProperty(OracleConnection.CONNECTION_PROPERTY_INTERNAL_LOGON, "SYSDBA"); - - } catch (SQLException sqlException) { - throw new AssertionError(sqlException); - } - } - - static void initDataSource(OracleDataSource dataSource, String url, String username, String password) { - dataSource.setURL(url); - dataSource.setUser(username); - dataSource.setPassword(password); - } - -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreAnnotatedTypeTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreAnnotatedTypeTest.java deleted file mode 100644 index e0332950b..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreAnnotatedTypeTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; - -public class OracleVectorStoreAnnotatedTypeTest extends OracleCommonVectorStoreRecordCollectionTest { - - @ParameterizedTest - @MethodSource("supportedDataTypes") - void testDataTypes(String dataFieldName, Class dataFieldType, Object dataFieldValue, Class fieldSubType) { - VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField.builder() - .withName("id") - .withStorageName("id") - .withFieldType(String.class) - .build(); - - VectorStoreRecordDataField dataField; - if (fieldSubType != null) { - dataField = VectorStoreRecordDataField.builder() - .withName("value") - .withStorageName("value_field") - .withFieldType(dataFieldType, fieldSubType) - .isFilterable(true) - .build(); - } else { - dataField = VectorStoreRecordDataField.builder() - .withName("value") - .withStorageName("value_field") - .withFieldType(dataFieldType) - .isFilterable(true) - .build(); - } - VectorStoreRecordDataField dataTypeField; - dataTypeField = VectorStoreRecordDataField.builder() - .withName("valueType") - .withStorageName("value_type") - .withFieldType(String.class) - .isFilterable(false) - .build(); - - - VectorStoreRecordVectorField dummyVector = VectorStoreRecordVectorField.builder() - .withName("vectorValue") - .withStorageName("vectorValue") - .withFieldType(Float[].class) - .withDimensions(8) - .withDistanceFunction(DistanceFunction.COSINE_DISTANCE) - .withIndexKind(IndexKind.IVFFLAT) - .build(); - - VectorStoreRecordDefinition definition = VectorStoreRecordDefinition.fromFields( - Arrays.asList(keyField, dataTypeField, dataField, dummyVector) - ); - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - String collectionName = "test_datatype_" + dataFieldName; - - VectorStoreRecordCollection collection = - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions. builder() - .withRecordClass(ClassWithAnnotatedTypes.class) - .withRecordDefinition(definition).build()); - - collection.createCollectionAsync().block(); - - String key = "testid"; - - ClassWithAnnotatedTypes record = - new ClassWithAnnotatedTypes(key, dataFieldName, dataFieldValue, new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f }); - - collection.upsertAsync(record, null).block(); - - ClassWithAnnotatedTypes result = collection.getAsync(key, null).block(); - assertNotNull(result); - if (record.getValue().getClass().equals(OffsetDateTime.class)) { - assertTrue(((OffsetDateTime)dataFieldValue).isEqual((OffsetDateTime)record.getValue())); - } else if (dataFieldName == "byte_array") { - assertArrayEquals((byte[]) dataFieldValue, (byte[])record.getValue()); - } else { - assertEquals(dataFieldValue, result.getValue()); - } - - collection.deleteCollectionAsync().block(); - } - - private static Stream supportedDataTypes() { - return Stream.of( - Arguments.of("string", String.class, "asd123", null), - Arguments.of("boolean", Boolean.class, true, null), - Arguments.of("boolean", Boolean.class, false, null), - Arguments.of("byte", Byte.class, (byte) 127, null), - Arguments.of("short", Short.class, (short) 3, null), - Arguments.of("integer", Integer.class, 321, null), - Arguments.of("long", Long.class, 5L, null), - Arguments.of("float", Float.class, 3.14f, null), - Arguments.of("double", Double.class, 3.14159265358d, null), - Arguments.of("decimal", BigDecimal.class, new BigDecimal("12345.67"), null), - Arguments.of("timestamp", OffsetDateTime.class, OffsetDateTime.now(), null), - Arguments.of("uuid", UUID.class, UUID.randomUUID(), null), - Arguments.of("byte_array", byte[].class, new byte[] {1, 2, 3}, String.class), - Arguments.of("json", List.class, Arrays.asList("a", "s", "d"), String.class) - ); - } - -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeSearchTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeSearchTest.java deleted file mode 100644 index bac0ee4c3..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeSearchTest.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.UUID; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class OracleVectorStoreDataTypeSearchTest extends OracleCommonVectorStoreRecordCollectionTest { - private static final double MIN_DOUBLE = 1.0E-130; - private static final double MIN_DECIMAL = -1.0E125; - private static final BigDecimal BIG_NUMBER = BigDecimal.valueOf(9999999999999999.99); - - - - @ParameterizedTest - @MethodSource("supportedDataTypes") - void testDataTypesSearch (ClassWithAllBoxedTypes record) { - VectorStoreRecordCollection collection = setupBoxed(); - - collection.upsertAsync(record, null).block(); - - // boolean - VectorSearchResults results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("booleanValue", record.getBooleanValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getBooleanValue(), results.getResults().get(0).getRecord().getBooleanValue()); - - // byte - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("byteValue", record.getByteValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getByteValue(), results.getResults().get(0).getRecord().getByteValue()); - - // short - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("shortValue", record.getShortValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getShortValue(), results.getResults().get(0).getRecord().getShortValue()); - - // integer - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("integerValue", record.getIntegerValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getIntegerValue(), results.getResults().get(0).getRecord().getIntegerValue()); - - // long - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("longValue", record.getLongValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getLongValue(), results.getResults().get(0).getRecord().getLongValue()); - - // float - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("floatValue", record.getFloatValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getFloatValue(), results.getResults().get(0).getRecord().getFloatValue()); - - // double - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("doubleValue", record.getDoubleValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getDoubleValue(), results.getResults().get(0).getRecord().getDoubleValue()); - - // decimal - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("decimalValue", record.getDecimalValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - if (record.getDecimalValue() != null) { - assertEquals(0, record.getDecimalValue() - .compareTo(results.getResults().get(0).getRecord().getDecimalValue())); - } else { - assertEquals(record.getDecimalValue(), - results.getResults().get(0).getRecord().getDecimalValue()); - } - - // offset date time - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("offsetDateTimeValue", record.getOffsetDateTimeValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - if (record.getOffsetDateTimeValue() != null) { - assertTrue(record.getOffsetDateTimeValue() - .isEqual(results.getResults().get(0).getRecord().getOffsetDateTimeValue())); - } else { - assertEquals(record.getOffsetDateTimeValue(), - results.getResults().get(0).getRecord().getOffsetDateTimeValue()); - } - - // UUID - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("uuidValue", record.getUuidValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals(record.getUuidValue(), results.getResults().get(0).getRecord().getUuidValue()); - - // byte array - results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("byteArrayValue", record.getByteArrayValue()).build() - ).build()).block(); - - assertEquals(1, results.getTotalCount()); - assertArrayEquals(record.getByteArrayValue(), results.getResults().get(0).getRecord().getByteArrayValue()); - - collection.deleteCollectionAsync().block(); - - } - - - public VectorStoreRecordCollection setupBoxed() { - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - VectorStoreRecordCollection collection = - vectorStore.getCollection("BoxedTypes", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(ClassWithAllBoxedTypes.class) - .build()).createCollectionAsync().block(); - - collection.createCollectionAsync().block(); - - return collection; - } - - - private static Stream supportedDataTypes() { - return Stream.of( - Arguments.of( - new ClassWithAllBoxedTypes( - "ID1", true, (byte) 127, (short) 3, 321, 5L, - 3.14f, 3.14159265358d, new BigDecimal("12345.67"), - OffsetDateTime.now(), UUID.randomUUID(), "abc".getBytes(StandardCharsets.UTF_8), - Arrays.asList(1.0f, 2.6f), - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID2", false, Byte.MIN_VALUE, Short.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE, - Float.MIN_VALUE, MIN_DOUBLE, BigDecimal.valueOf(MIN_DECIMAL), - OffsetDateTime.now(), UUID.randomUUID(), new byte[] {Byte.MIN_VALUE, -10, 0, 10, Byte.MAX_VALUE}, - Arrays.asList(Float.MIN_VALUE, -10f, 0f, 10f, Float.MAX_VALUE), - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID3", false, Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, - Float.MAX_VALUE, BIG_NUMBER.doubleValue(), BIG_NUMBER.subtract(BigDecimal.valueOf(0.01d)), - OffsetDateTime.now(), UUID.randomUUID(), null, - null, - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID3", null, null, null, null, null, - null, null, null, - null, null, null, - null, - null - ) - ) - ); - } - - private static Stream supportedDataPrimitiveTypes() { - return Stream.of( - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID1", true, (byte) 127, (short) 3, 321, 5L, - 3.14f, 3.14159265358d, new BigDecimal("12345.67"), - OffsetDateTime.now(), UUID.randomUUID(), "abc".getBytes(StandardCharsets.UTF_8), - Arrays.asList(1.0f, 2.6f), - new float[]{0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f} - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID2", false, Byte.MIN_VALUE, Short.MIN_VALUE, Integer.MIN_VALUE, - Long.MIN_VALUE, - Float.MIN_VALUE, MIN_DOUBLE, BigDecimal.valueOf(MIN_DECIMAL), - OffsetDateTime.now(), UUID.randomUUID(), - new byte[]{Byte.MIN_VALUE, -10, 0, 10, Byte.MAX_VALUE}, - Arrays.asList(Float.MIN_VALUE, -10f, 0f, 10f, Float.MAX_VALUE), - new float[]{0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f} - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID3", false, Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, - Long.MAX_VALUE, - Float.MAX_VALUE, BIG_NUMBER.doubleValue(), - BIG_NUMBER.subtract(BigDecimal.valueOf(0.01d)), - OffsetDateTime.now(), UUID.randomUUID(), null, - null, - new float[]{0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f} - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID3", false, (byte) 0, (short) 0, 0, 0l, - 0f, 0d, null, - null, null, null, - null, - null - ) - ) - ); - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeTest.java deleted file mode 100644 index eeb6a2e7b..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreDataTypeTest.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.UUID; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class OracleVectorStoreDataTypeTest extends OracleCommonVectorStoreRecordCollectionTest { - private static final double MIN_NUMBER = 1.0E-130; - private static final BigDecimal BIG_NUMBER = BigDecimal.valueOf(9999999999999999.99); - - @ParameterizedTest - @MethodSource("supportedDataTypes") - void testDataTypes(ClassWithAllBoxedTypes values) { - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - VectorStoreRecordCollection collection = - vectorStore.getCollection("BoxedTypes", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(ClassWithAllBoxedTypes.class) - .build()).createCollectionAsync().block(); - - collection.createCollectionAsync().block(); - - ClassWithAllBoxedTypes record = values; - - collection.upsertAsync(record, null).block(); - - ClassWithAllBoxedTypes result = collection.getAsync(values.getId(), null).block(); - assertNotNull(result); - - assertEquals(values.getBooleanValue(), result.getBooleanValue()); - assertArrayEquals(values.getByteArrayValue(), result.getByteArrayValue()); - assertEquals(values.getByteValue(), result.getByteValue()); - assertEquals(values.getDoubleValue(), result.getDoubleValue()); - assertEquals(values.getFloatValue(), result.getFloatValue()); - assertEquals(values.getIntegerValue(), result.getIntegerValue()); - assertEquals(values.getListOfFloatValue(), result.getListOfFloatValue()); - assertEquals(values.getLongValue(), result.getLongValue()); - if (values.getOffsetDateTimeValue() != null) { - assertTrue(values.getOffsetDateTimeValue().isEqual(result.getOffsetDateTimeValue())); - } else { - assertTrue(result.getOffsetDateTimeValue() == null); - } - assertEquals(values.getShortValue(), result.getShortValue()); - assertEquals(values.getUuidValue(), result.getUuidValue()); - - collection.deleteCollectionAsync().block(); - } - - @ParameterizedTest - @MethodSource("supportedDataPrimitiveTypes") - void testPrimitiveDataTypes(ClassWithAllPrimitiveTypes values) { - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - VectorStoreRecordCollection collection = - vectorStore.getCollection("PrimitiveTypes", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(ClassWithAllPrimitiveTypes.class) - .build()).createCollectionAsync().block(); - - collection.createCollectionAsync().block(); - - ClassWithAllPrimitiveTypes record = values; - - collection.upsertAsync(record, null).block(); - - ClassWithAllPrimitiveTypes result = collection.getAsync(values.getId(), null).block(); - assertNotNull(result); - - assertEquals(values.getBooleanValue(), result.getBooleanValue()); - assertArrayEquals(values.getByteArrayValue(), result.getByteArrayValue()); - assertEquals(values.getByteValue(), result.getByteValue()); - assertEquals(values.getDoubleValue(), result.getDoubleValue()); - assertEquals(values.getFloatValue(), result.getFloatValue()); - assertEquals(values.getIntegerValue(), result.getIntegerValue()); - assertEquals(values.getListOfFloatValue(), result.getListOfFloatValue()); - assertEquals(values.getLongValue(), result.getLongValue()); - if (values.getOffsetDateTimeValue() != null) { - assertTrue(values.getOffsetDateTimeValue().isEqual(result.getOffsetDateTimeValue())); - } else { - assertTrue(result.getOffsetDateTimeValue() == null); - } - assertEquals(values.getShortValue(), result.getShortValue()); - assertEquals(values.getUuidValue(), result.getUuidValue()); - - collection.deleteCollectionAsync().block(); - } - - - private static Stream supportedDataTypes() { - return Stream.of( - Arguments.of( - new ClassWithAllBoxedTypes( - "ID1", true, (byte) 127, (short) 3, 321, 5L, - 3.14f, 3.14159265358d, new BigDecimal("12345.67"), - OffsetDateTime.now(), UUID.randomUUID(), "abc".getBytes(StandardCharsets.UTF_8), - Arrays.asList(1.0f, 2.6f), - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID2", false, Byte.MIN_VALUE, Short.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE, - Float.MIN_VALUE, MIN_NUMBER, BigDecimal.valueOf(MIN_NUMBER), - OffsetDateTime.now(), UUID.randomUUID(), new byte[] {Byte.MIN_VALUE, -10, 0, 10, Byte.MAX_VALUE}, - Arrays.asList(Float.MIN_VALUE, -10f, 0f, 10f, Float.MAX_VALUE), - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID3", false, Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, - Float.MAX_VALUE, BIG_NUMBER.doubleValue(), BIG_NUMBER.subtract(BigDecimal.valueOf(0.01d)), - OffsetDateTime.now(), UUID.randomUUID(), null, - null, - new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllBoxedTypes( - "ID3", null, null, null, null, null, - null, null, null, - null, null, null, - null, - null - ) - ) - ); - } - - private static Stream supportedDataPrimitiveTypes() { - return Stream.of( - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID1", true, (byte) 127, (short) 3, 321, 5L, - 3.14f, 3.14159265358d, new BigDecimal("12345.67"), - OffsetDateTime.now(), UUID.randomUUID(), "abc".getBytes(StandardCharsets.UTF_8), - Arrays.asList(1.0f, 2.6f), - new float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID2", false, Byte.MIN_VALUE, Short.MIN_VALUE, Integer.MIN_VALUE, Long.MIN_VALUE, - Float.MIN_VALUE, MIN_NUMBER, BigDecimal.valueOf(MIN_NUMBER), - OffsetDateTime.now(), UUID.randomUUID(), new byte[] {Byte.MIN_VALUE, -10, 0, 10, Byte.MAX_VALUE}, - Arrays.asList(Float.MIN_VALUE, -10f, 0f, 10f, Float.MAX_VALUE), - new float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID3", false, Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, - Float.MAX_VALUE, BIG_NUMBER.doubleValue(), BIG_NUMBER.subtract(BigDecimal.valueOf(0.01d)), - OffsetDateTime.now(), UUID.randomUUID(), null, - null, - new float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f } - ) - ), - Arguments.of( - new ClassWithAllPrimitiveTypes( - "ID3", false, (byte)0, (short)0, 0, 0l, - 0f, 0d, null, - null, null, null, - null, - null - ) - ) - ); - } - -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreExtendedTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreExtendedTest.java deleted file mode 100644 index af2e28fd8..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreExtendedTest.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.oracle.OracleVectorStoreQueryProvider.StringTypeMapping; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; - -import org.junit.jupiter.api.Test; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class OracleVectorStoreExtendedTest extends OracleCommonVectorStoreRecordCollectionTest { - - // Test vector types - @Test - void testUseStringVec() { - VectorStoreRecordCollection collection = - createCollection( - "use_string_vec", - DummyRecordForVecString.class, - null); - - DummyRecordForVecString d1 = new DummyRecordForVecString("id1", "description1", "[1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8]"); - DummyRecordForVecString d2 = new DummyRecordForVecString("id2", "description2", "[1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8]"); - - collection.upsertBatchAsync(Arrays.asList(d1,d2), null).block(); - - DummyRecordForVecString rec = collection.getAsync("id1", - GetRecordOptions.builder().includeVectors(true).build()).block(); - - assertNotNull(rec); - assertEquals("[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8]", rec.getVec()); - - collection.deleteCollectionAsync().block(); - } - - @Test - void testUseCollectionVec() { - VectorStoreRecordCollection collection = - createCollection( - "use_collection_vec", - DummyRecordForVecCollection.class, - null); - - List v1 = Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10f, -1.3f, 5.5f); - List v2 = Arrays.asList(-2f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f); - DummyRecordForVecCollection d1 = new DummyRecordForVecCollection("id1", "", v1); - DummyRecordForVecCollection d2 = new DummyRecordForVecCollection("id2", "", v2); - - collection.upsertBatchAsync(Arrays.asList(d1,d2), null).block(); - - DummyRecordForVecCollection rec = collection.getAsync("id1", - GetRecordOptions.builder().includeVectors(true).build()).block(); - - assertNotNull(rec); - assertEquals(8, rec.getVec().size()); - assertIterableEquals(v1, rec.getVec()); - - collection.deleteCollectionAsync().block(); - } - - // Test corner-case - @Test - void testUseCLOB() { - VectorStoreRecordCollection collection = - createCollection( - "use_clob", - DummyRecordForCLOB.class, - OracleVectorStoreQueryProvider.StringTypeMapping.USE_CLOB); - - DummyRecordForCLOB d1 = new DummyRecordForCLOB("id1", "clob-description", null); - DummyRecordForCLOB d2 = new DummyRecordForCLOB("id2", "clob-description2", vec(0)); - - collection.upsertBatchAsync(Arrays.asList(d1,d2), null).block(); - - try (Connection c = DATA_SOURCE.getConnection()) { - PreparedStatement st = c.prepareStatement( - "SELECT DATA_TYPE FROM USER_TAB_COLUMNS " + - "WHERE TABLE_NAME = 'SKCOLLECTION_USE_CLOB' AND COLUMN_NAME = 'DESCRIPTION'" - ); - ResultSet rs = st.executeQuery(); - rs.next(); - assertEquals("CLOB", rs.getString(1)); - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - collection.deleteCollectionAsync().block(); - } - } - - @Test - void testClobLongText() { - VectorStoreRecordCollection collection = - createCollection( - "clob_long_text", - DummyRecordForCLOB.class, - OracleVectorStoreQueryProvider.StringTypeMapping.USE_CLOB); - - String longText = String.join("", java.util.Collections.nCopies(6000, "a")); - DummyRecordForCLOB r = new DummyRecordForCLOB("big", longText, vec(0)); - collection.upsertAsync(r, null).block(); - - DummyRecordForCLOB out = collection.getAsync("big", null).block(); - assertEquals(longText.length(), out.getDescription().length()); - assertTrue(out.getDescription().startsWith("aaaa")); - - collection.deleteCollectionAsync().block(); - } - - @Test - void testMultipleFilter() { - VectorStoreRecordCollection collection = - createCollection( - "multiple_filter", - DummyRecordForMultipleFilter.class, - null); - - DummyRecordForMultipleFilter d1 = new DummyRecordForMultipleFilter("id1", 4, 120, floatVec(0f)); - DummyRecordForMultipleFilter d2 = new DummyRecordForMultipleFilter("id2", 4, 100, floatVec(0f)); - DummyRecordForMultipleFilter d3 = new DummyRecordForMultipleFilter("id3", 3, 100, floatVec(0f)); - - collection.upsertBatchAsync(Arrays.asList(d1,d2,d3), null).block(); - - VectorSearchFilter filter = VectorSearchFilter.builder() - .equalTo("price",100) - .equalTo("stars", 4) - .build(); - - VectorSearchResults results = - collection.searchAsync(null, - VectorSearchOptions.builder() - .withVectorSearchFilter(filter) - .build() - ).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals("id2", results.getResults().get(0).getRecord().getId()); - - collection.deleteCollectionAsync().block(); - } - - @Test - void testVectorDimensionMismatch() { - VectorStoreRecordCollection collection = - createCollection( - "vector_dimension_mismatch", - DummyRecord.class, - null); - - // Empty vector rejected - DummyRecord d1 = new DummyRecord("id1", 4, 120d, new float[]{}); - SKException ex = assertThrows(SKException.class, - () -> collection.upsertBatchAsync(Arrays.asList(d1), null).block()); - assertTrue(ex.getCause().getMessage().contains("ORA-51803")); - - // Vector dimension mismatch - DummyRecord d2 = new DummyRecord("id1", 4, 120d, new float[]{1.1f,2.2f,3.3f,4.4f,5.5f}); - SKException ex2 = assertThrows(SKException.class, - () -> collection.upsertBatchAsync(Arrays.asList(d2), null).block()); - assertTrue(ex2.getCause().getMessage().contains("ORA-51803")); - - collection.deleteCollectionAsync().block(); - } - - @Test - void testNullFieldValue() { - VectorStoreRecordCollection collection = - createCollection("test_null", DummyRecord.class, null); - - DummyRecord d1 = new DummyRecord("id1", 4, null, floatVec(1)); - collection.upsertBatchAsync(Arrays.asList(d1), null).block(); - - VectorSearchFilter filter = VectorSearchFilter.builder() - .equalTo("price",null)// - .build(); - - VectorSearchResults results = collection.searchAsync( - null, - VectorSearchOptions.builder() - .withVectorSearchFilter(filter) - .build() - ).block(); - - assertEquals(1, results.getTotalCount()); - assertEquals("id1", results.getResults().get(0).getRecord().getId()); - - collection.deleteCollectionAsync().block(); - } - - @Test - void testSkipAndTop() { - VectorStoreRecordCollection collection = - createCollection( - "test_skip_and_top", - DummyRecord.class, - null); - - List l1 = new ArrayList<>(); - for (int i = 1; i <= 10; i++) { - l1.add(new DummyRecord("id" + i, i, (double) i, floatVec(i))); - } - collection.upsertBatchAsync(l1, null).block(); - - VectorSearchResults results = collection.searchAsync( - Collections.nCopies(8,0f), - VectorSearchOptions.builder() - .withIncludeVectors(true) - .withSkip(5) - .withTop(3) - .build() - ).block(); - - assertEquals(3, results.getResults().size()); - List ids = results.getResults().stream().map(r -> r.getRecord().getId()).collect( - Collectors.toList()); - assertEquals(Arrays.asList("id6","id7","id8"), ids); - - collection.deleteCollectionAsync().block(); - } - - // corner case for OracleVectorStoreRecordMapper - @Test - void testMapRecordToStorageModel_throws() { - VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField.builder() - .withName("id") - .withStorageName("id") - .withFieldType(String.class) - .build(); - - VectorStoreRecordDefinition definition = - VectorStoreRecordDefinition.fromFields( - Arrays.asList(keyField) - ); - - OracleVectorStoreRecordMapper mapper = - OracleVectorStoreRecordMapper. builder() - .withRecordClass(DummyRecord.class) - .withVectorStoreRecordDefinition(definition) - .build(); - - UnsupportedOperationException ex = assertThrows( - UnsupportedOperationException.class, - () -> mapper.mapRecordToStorageModel(new DummyRecord())); - assertEquals("Not implemented", ex.getMessage()); - } - - private VectorStoreRecordCollection createCollection( - String collectionName, - Class recordClass, - OracleVectorStoreQueryProvider.StringTypeMapping stringTypeMapping) { - - OracleVectorStoreQueryProvider.Builder builder = - OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE); - - if (stringTypeMapping != null) { - builder.withStringTypeMapping(stringTypeMapping); - } - OracleVectorStoreQueryProvider queryProvider = builder.build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - VectorStoreRecordCollection collection = - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(recordClass) - .build()).createCollectionAsync().block(); - - return collection; - } - - private List vec(float x) { - return Arrays.asList(x, x+1, x+2, x+3, x+4, x+5, x+6, x+7); - } - - private float[] floatVec(float x) { - return new float[] { x, x+1, x+2, x+3, x+4, x+5, x+6, x+7 }; - } - - private static class DummyRecordForVecString { - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = false) - private final String description; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private final String vec; - - public DummyRecordForVecString() { - this(null, null, null); - } - public DummyRecordForVecString(String id, String description, String vec) { - this.id = id; - this.description = description; - this.vec = vec; - } - - public String getId() { - return id; - } - public String getDescription() { - return description; - } - public String getVec() { - return vec; - } - } - - private static class DummyRecordForVecCollection{ - @VectorStoreRecordKey - private String id; - - @VectorStoreRecordData(isFilterable = false) - private String description; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private Collection vec; - - public DummyRecordForVecCollection() { - this(null, null, null); - } - public DummyRecordForVecCollection(String id, String description, Collection vec) { - this.id = id; - this.description = description; - this.vec = vec; - } - - public String getId() { - return id; - } - public String getDescription() { - return description; - } - public Collection getVec() { - return vec; - } - } - - private static class DummyRecordForCLOB { - @VectorStoreRecordKey - private String id; - - @VectorStoreRecordData(isFilterable = false) - private String description; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private List vec; - - private DummyRecordForCLOB() { - this(null, null, null); - } - private DummyRecordForCLOB(String id, String description, List vec) { - this.id = id; - this.description = description; - this.vec = vec; - } - - public String getId() { - return id; - } - public String getDescription() { - return description; - } - public List getVec() { - return vec; - } - } - - private static class DummyRecordForMultipleFilter { - @VectorStoreRecordKey - private String id; - - @VectorStoreRecordData(isFilterable = true) - private int stars; - - @VectorStoreRecordData(isFilterable = true) - private double price; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private float[] vec; - - public DummyRecordForMultipleFilter() { - this(null, 0, 0d, null); - } - - public DummyRecordForMultipleFilter(String id, int stars, double price, float[] vec) { - this.id = id; - this.stars = stars; - this.price = price; - this.vec = vec; - } - - public String getId() { - return id; - } - public int getStars() { - return stars; - } - public double getPrice() { - return price; - } - public float[] getVec() { - return vec; - } - } - - private static class DummyRecord { - @VectorStoreRecordKey - private String id; - - @VectorStoreRecordData(isFilterable = true) - private int stars; - - @VectorStoreRecordData(isFilterable = true) - private Double price; - - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE, indexKind = IndexKind.IVFFLAT) - private float[] vec; - - public DummyRecord() { - this(null, 0, 0d, null); - } - - public DummyRecord(String id, int stars, Double price, float[] vec) { - this.id = id; - this.stars = stars; - this.price = price; - this.vec = vec; - } - - public String getId() { - return id; - } - public int getStars() { - return stars; - } - public Double getPrice() { - return price; - } - public float[] getVec() { - return vec; - } - } -} diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordCollectionTest.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordCollectionTest.java deleted file mode 100644 index 850ae9238..000000000 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/OracleVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,592 +0,0 @@ -package com.microsoft.semantickernel.data.jdbc.oracle; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class OracleVectorStoreRecordCollectionTest extends OracleCommonVectorStoreRecordCollectionTest { - private static VectorStoreRecordCollection recordCollection; - - @BeforeAll - public static void setup() throws Exception { - - // Build a query provider - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - // Build a vector store - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - // Get a collection from the vector store - recordCollection = - vectorStore.getCollection("skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - recordCollection.createCollectionIfNotExistsAsync().block(); - } - - @BeforeEach - public void clearCollection() { - recordCollection.deleteCollectionAsync().block(); - recordCollection.createCollectionAsync().block(); - } - - private static List getHotels() { - List vec1 = Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f); - float[] arrayf1 = new float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f }; - Float[] arrayF1 = new Float[] { 0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f }; - List vec2 = Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f); - float[] arrayf2 = new float[] { -2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f }; - Float[] arrayF2 = new Float[] { -2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f }; - List vec3 = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f); - float[] arrayf3 = new float[] { 4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f }; - Float[] arrayF3 = new Float[] { 4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f }; - List vec4 = Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f); - float[] arrayf4 = new float[] { 7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f }; - Float[] arrayF4 = new Float[] { 7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f }; - List vec5 =Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f); - float[] arrayf5 = new float[] { -3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f }; - Float[] arrayF5 = new Float[] { -3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f }; - return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, 1.49d, Arrays.asList("one", "two"), "Hotel 1 description", - vec1, arrayf1, arrayf1, arrayF1, - 4.0), - new Hotel("id_2", "Hotel 2", 2, 1.44d, Arrays.asList("three", "four"), "Hotel 2 description with free-text search", - vec2, arrayf2, arrayf2, arrayF2, - 4.0), - new Hotel("id_3", "Hotel 3", 3, 1.53d, Arrays.asList("five", "six"), "Hotel 3 description", - vec3, arrayf3, arrayf3, arrayF3, - 5.0), - new Hotel("id_4", "Hotel 4", 4, 1.35d, Arrays.asList("seven", "eight"), "Hotel 4 description", - vec4, arrayf4, arrayf4, arrayF4, - 4.0), - new Hotel("id_5", "Hotel 5", 5, 1.89d, Arrays.asList("nine", "ten"),"Hotel 5 description", - vec5, arrayf5, arrayf5, arrayF5, - 4.0)); - } - - /** - * Search embeddings similar to the third hotel embeddings. - * In order of similarity: - * 1. Hotel 3 - * 2. Hotel 1 - * 3. Hotel 4 - */ - private static final List SEARCH_EMBEDDINGS = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, - -0.8f, 1.1f, -2.2f, 8.2f); - - @Test - public void createAndDeleteCollectionAsync() { - assertEquals(true, recordCollection.collectionExistsAsync().block()); - - recordCollection.deleteCollectionAsync().block(); - assertEquals(false, recordCollection.collectionExistsAsync().block()); - - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - } - - @Test - public void upsertRecordAsync() { - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getName(), retrievedHotel.getName()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @Test - public void upsertBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getName(), retrievedHotel.getName()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @Test - public void getBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = hotels.stream().map(Hotel::getId).collect(Collectors.toList()); - List retrievedHotels = recordCollection.getBatchAsync(keys, null).block(); - - assertNotNull(retrievedHotels); - assertEquals(keys.size(), retrievedHotels.size()); - for (Hotel hotel : retrievedHotels) { - assertTrue(keys.contains(hotel.getId())); - } - } - - @Test - public void deleteRecordAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - recordCollection.deleteAsync(hotel.getId(), null).block(); - assertNull(recordCollection.getAsync(hotel.getId(), null).block()); - } - } - - @Test - public void deleteBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = hotels.stream().map(Hotel::getId).collect(Collectors.toList()); - recordCollection.deleteBatchAsync(keys, null).block(); - - for (String key : keys) { - assertNull(recordCollection.getAsync(key, null).block()); - } - } - - @ParameterizedTest - @MethodSource("parametersExactSearch") - public void exactSearch(DistanceFunction distanceFunction, List expectedDistance) { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withTop(3) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection - .searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId()); - assertEquals(expectedDistance.get(0).doubleValue(), results.get(0).getScore(), 0.0002d); - assertEquals(hotels.get(0).getId(), results.get(1).getRecord().getId()); - assertEquals(expectedDistance.get(1).doubleValue(), results.get(1).getScore(), 0.0002d); - assertEquals(hotels.get(3).getId(), results.get(2).getRecord().getId()); - assertEquals(expectedDistance.get(2).doubleValue(), results.get(2).getScore(), 0.0002d); - - options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withSkip(1) - .withTop(-100) - .build(); - - // Skip the first result - results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(1, results.size()); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId()); - assertEquals(results.get(0).getScore(), expectedDistance.get(1), 0.001d); - } - - @ParameterizedTest - @MethodSource("distanceFunctionAndDistance") - public void searchWithFilter(DistanceFunction distanceFunction, double expectedDistance) { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection - .searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId()); - assertEquals(results.get(0).getScore(), expectedDistance, 0.0002d); - } - - - @Test - public void searchWithTagFilter() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() -// .withVectorFieldName("") - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .anyTagEqualTo("tags", "three") - .build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection - .searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(1, results.size()); - // The second hotel contains the tag we are searching for - assertEquals(hotels.get(1).getId(), results.get(0).getRecord().getId()); - } - - @ParameterizedTest - @MethodSource("supportedKeyTypes") - void testKeyTypes(String suffix, Class keyType, Object keyValue) { - VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField.builder() - .withName("id") - .withStorageName("id") - .withFieldType(keyType) - .build(); - - VectorStoreRecordDataField dummyField = VectorStoreRecordDataField.builder() - .withName("dummy") - .withStorageName("dummy") - .withFieldType(String.class) - .build(); - - VectorStoreRecordVectorField dummyVector = VectorStoreRecordVectorField.builder() - .withName("vec") - .withStorageName("vec") - .withFieldType(List.class) - .withDimensions(2) - .withDistanceFunction(DistanceFunction.EUCLIDEAN_DISTANCE) - .withIndexKind(IndexKind.UNDEFINED) - .build(); - - VectorStoreRecordDefinition definition = VectorStoreRecordDefinition.fromFields( - Arrays.asList(keyField, dummyField, dummyVector) - ); - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - String collectionName = "test_keytype_" + suffix; - - VectorStoreRecordCollection collectionRaw = - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(DummyRecordForKeyTypes.class) - .withRecordDefinition(definition) - .build()); - - VectorStoreRecordCollection collection = - (VectorStoreRecordCollection) collectionRaw; - - collection.createCollectionAsync().block(); - - DummyRecordForKeyTypes record = new DummyRecordForKeyTypes(keyValue, "dummyValue", Arrays.asList(1.0f, 2.0f)); - collection.upsertAsync(record, null).block(); - - DummyRecordForKeyTypes result = collection.getAsync(keyValue, null).block(); - assertNotNull(result); - assertEquals("dummyValue", result.getDummy()); - - collection.deleteCollectionAsync().block(); - } - - - @Nested - class HNSWIndexTests { - @Test - void testHNSWIndexIsCreatedSuccessfully() throws Exception { - VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField.builder() - .withName("id") - .withStorageName("id") - .withFieldType(String.class) - .build(); - - VectorStoreRecordDataField dummyField = VectorStoreRecordDataField.builder() - .withName("dummy") - .withStorageName("dummy") - .withFieldType(String.class) - .isFilterable(false) - .build(); - - VectorStoreRecordVectorField hnswVector= VectorStoreRecordVectorField.builder() - .withName("hnsw") - .withStorageName("hnsw") - .withFieldType(List.class) - .withDimensions(8) - .withDistanceFunction(DistanceFunction.COSINE_SIMILARITY) - .withIndexKind(IndexKind.HNSW) - .build(); - - VectorStoreRecordDefinition definition = VectorStoreRecordDefinition.fromFields( - Arrays.asList(keyField, dummyField, hnswVector) - ); - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - String collectionName = "skhotels_hnsw"; - VectorStoreRecordCollection collection = - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Object.class) - .withRecordDefinition(definition) - .build()); - - // create collection - collection.createCollectionAsync().block(); - - String expectedIndexName = hnswVector.getEffectiveStorageName().toUpperCase() + "_VECTOR_INDEX"; - - // check if index exist - try (Connection conn = DATA_SOURCE.getConnection(); - PreparedStatement stmt = conn.prepareStatement( - "SELECT COUNT(*) FROM USER_INDEXES WHERE INDEX_NAME=?")) { - stmt.setString(1, expectedIndexName); - ResultSet rs = stmt.executeQuery(); - rs.next(); - int count = rs.getInt(1); - - assertEquals(1, count, "hnsw vector index should have been created"); - } finally { - // clean up - try (Connection conn = DATA_SOURCE.getConnection(); - Statement stmt = conn.createStatement()) { - stmt.executeUpdate("DROP TABLE " + "SKCOLLECTION_" + collectionName); - } - } - } - } - - @Nested - class UndefinedIndexTests { - @Test - void testNoIndexIsCreatedForUndefined() throws Exception { - // create key field - VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField.builder() - .withName("id") - .withStorageName("id") - .withFieldType(String.class) - .build(); - - // create vector field, set IndexKind to UNDEFINED - VectorStoreRecordVectorField undefinedVector= VectorStoreRecordVectorField.builder() - .withName("undef") - .withStorageName("undef") - .withFieldType(List.class) - .withDimensions(8) - .withDistanceFunction(DistanceFunction.COSINE_SIMILARITY) - .withIndexKind(IndexKind.UNDEFINED) - .build(); - - VectorStoreRecordDataField dummyField = VectorStoreRecordDataField.builder() - .withName("dummy") - .withStorageName("dummy") - .withFieldType(String.class) - .isFilterable(false) - .build(); - - VectorStoreRecordDefinition definition = VectorStoreRecordDefinition.fromFields( - Arrays.asList(keyField, dummyField, undefinedVector) - ); - - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(DATA_SOURCE) - .build(); - - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(DATA_SOURCE) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - String collectionName = "skhotels_undefined"; - VectorStoreRecordCollection collection = - vectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Object.class) - .withRecordDefinition(definition) - .build()); - - // create collection - collection.createCollectionAsync().block(); - - // check if index exist - String expectedIndexName = undefinedVector.getEffectiveStorageName().toUpperCase() + "_VETCOR_INDEX"; - try (Connection conn = DATA_SOURCE.getConnection(); - PreparedStatement stmt = conn.prepareStatement( - "SELECT COUNT(*) FROM USER_INDEXES WHERE INDEX_NAME = ?")) { - stmt.setString(1, expectedIndexName); - ResultSet rs = stmt.executeQuery(); - rs.next(); - int count = rs.getInt(1); - - assertEquals(0,count,"Vector index should not be created for IndexKind.UNDEFINED"); - } finally { - // clean up - try (Connection conn = DATA_SOURCE.getConnection(); - Statement stmt = conn.createStatement()) { - stmt.executeUpdate("DROP TABLE " + "SKCOLLECTION_" + collectionName); - } - } - } - } - - private static Stream distanceFunctionAndDistance() { - return Stream.of( - Arguments.of (DistanceFunction.COSINE_DISTANCE, 0.8548d), - Arguments.of (DistanceFunction.COSINE_SIMILARITY, 0.1451d), - Arguments.of (DistanceFunction.DOT_PRODUCT, 30.3399d), - Arguments.of (DistanceFunction.EUCLIDEAN_DISTANCE, 18.9081d), - Arguments.of (DistanceFunction.UNDEFINED, 18.9081d) - ); - } - - private static Stream parametersExactSearch() { - return Stream.of( - Arguments.of (DistanceFunction.COSINE_SIMILARITY, Arrays.asList(0.9999d, 0.1451d, 0.0178d)), - Arguments.of (DistanceFunction.COSINE_DISTANCE, Arrays.asList(1.6422E-5d, 0.8548d, 0.9821d)), - Arguments.of (DistanceFunction.DOT_PRODUCT, Arrays.asList(202.3399d, 30.3399d, 3.6199d)), - Arguments.of (DistanceFunction.EUCLIDEAN_DISTANCE, Arrays.asList(0.1000d, 18.9081d, 19.9669d)), - Arguments.of (DistanceFunction.UNDEFINED, Arrays.asList(0.1000d, 18.9081d, 19.9669d)) - ); - } - - // commented out temporarily because only String type key is supported in - // JDBCVectorStoreRecordCollection#getKeyFromRecord: - // ... - // return (String) keyField.get(data); - // ... - // thus upsertAync/getAsync won't work - private static Stream supportedKeyTypes() { - return Stream.of( - Arguments.of("string", String.class, "asd123") /*, - Arguments.of("integer", Integer.class, 321), - Arguments.of("long", Long.class, 5L), - Arguments.of("short", Short.class, (short) 3), - Arguments.of("uuid", UUID.class, UUID.randomUUID())*/ - ); - } - - private static class DummyRecordForKeyTypes { - private final Object id; - private final String dummy; - private final List vec; - @JsonCreator - public DummyRecordForKeyTypes( - @JsonProperty("id")Object id, - @JsonProperty("dummy") String dummy, - @JsonProperty("vec") List vec) { - this.id = id; - this.dummy = dummy; - this.vec = vec; - } - - public Object getId() { - return id; - } - - public String getDummy() { - return dummy; - } - - @Override - public String toString() { - return String.valueOf(id); - } - } - - private static class DummyRecordForDataTypes { - private final String id; - private final Object dummy; - private final List vec; - @JsonCreator - public DummyRecordForDataTypes( - @JsonProperty("id") String id, - @JsonProperty("dummy") Object dummy, - @JsonProperty("vec") List vec) { - this.id = id; - this.dummy = dummy; - this.vec = vec; - } - - public String getId() { - return id; - } - - public Object getDummy() { - return dummy; - } - - @Override - public String toString() { - return String.valueOf(id); - } - } -} diff --git a/data/semantickernel-data-oracle/src/test/resources/initialize.sql b/data/semantickernel-data-oracle/src/test/resources/initialize.sql deleted file mode 100644 index 8756f121d..000000000 --- a/data/semantickernel-data-oracle/src/test/resources/initialize.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Exit on any errors -WHENEVER SQLERROR EXIT SQL.SQLCODEAdd commentMore actions - --- Configure the size of the Vector Pool to 1 GiB. -ALTER SYSTEM SET vector_memory_size=1G SCOPE=SPFILE; - -sqlplus / as sysdba - -SHUTDOWN ABORT; -STARTUP; - -exit \ No newline at end of file diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml deleted file mode 100644 index 8f22241dc..000000000 --- a/data/semantickernel-data-postgres/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-data-postgres - Semantic Kernel PostreSQL connector - Provides a PostreSQL connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.postgresql - postgresql - 42.7.7 - - - \ No newline at end of file diff --git a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorDistanceFunction.java b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorDistanceFunction.java deleted file mode 100644 index 4ad2bd3b9..000000000 --- a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorDistanceFunction.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.postgres; - -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; - -/** - * Represents a PostgreSQL vector distance function. - */ -public enum PostgreSQLVectorDistanceFunction { - /** - * Euclidean L2 distance function. - */ - L2("vector_l2_ops", "<->"), - /** - * The cosine distance function. - */ - COSINE("vector_cosine_ops", "<=>"), - /** - * The inner product distance function. - */ - INNER_PRODUCT("vector_ip_ops", "<#>"), - /** - * The distance function is undefined. - */ - UNDEFINED(null, null); - - private final String value; - private final String operator; - - PostgreSQLVectorDistanceFunction(String value, String operator) { - this.value = value; - this.operator = operator; - } - - /** - * Gets the value of the distance function. - * @return the value of the distance function - */ - public String getValue() { - return value; - } - - /** - * Gets the operator of the distance function. - * @return the operator of the distance function - */ - public String getOperator() { - return operator; - } - - /** - * Converts a distance function to a PostgreSQL vector distance function. - * @param function the distance function - * @return the PostgreSQL vector distance function - */ - public static PostgreSQLVectorDistanceFunction fromDistanceFunction(DistanceFunction function) { - switch (function) { - case EUCLIDEAN_DISTANCE: - return L2; - case COSINE_DISTANCE: - return COSINE; - case DOT_PRODUCT: - return INNER_PRODUCT; - case UNDEFINED: - return UNDEFINED; - default: - throw new IllegalArgumentException("Unsupported distance function: " + function); - } - } -} diff --git a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorIndexKind.java b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorIndexKind.java deleted file mode 100644 index cd0681b87..000000000 --- a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorIndexKind.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.postgres; - -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -/** - * Represents a PostgreSQL vector index kind. - */ -public enum PostgreSQLVectorIndexKind { - /** - * The vector is indexed using an HNSW algorithm. - */ - HNSW("hnsw"), - /** - * The vector is indexed using a Flat algorithm. - */ - IVFFLAT("ivfflat"), - /** - * The indexing algorithm is undefined. - */ - UNDEFINED(null); - - private final String value; - - PostgreSQLVectorIndexKind(String value) { - this.value = value; - } - - /** - * Gets the pgvector value of the index kind. - * @return the pgvector value of the index kind - */ - public String getValue() { - return value; - } - - /** - * Converts an index kind to a PostgreSQL vector index kind. - * @param indexKind the index kind - * @return the PostgreSQL vector index kind - */ - public static PostgreSQLVectorIndexKind fromIndexKind(IndexKind indexKind) { - switch (indexKind) { - case HNSW: - return HNSW; - case IVFFLAT: - return IVFFLAT; - case FLAT: - case UNDEFINED: - return UNDEFINED; - default: - throw new IllegalArgumentException("Unsupported index kind: " + indexKind); - } - } -} diff --git a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java deleted file mode 100644 index 1f3273eb3..000000000 --- a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.postgres; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * The MySQL vector store query provider. - * Provides the necessary methods to interact with a MySQL - * vector store and vector store collections. - */ -public class PostgreSQLVectorStoreQueryProvider extends - JDBCVectorStoreQueryProvider implements SQLVectorStoreQueryProvider { - private final String collectionsTable; - private final String prefixForCollectionTables; - private final ObjectMapper objectMapper; - - @SuppressFBWarnings("EI_EXPOSE_REP2") - private PostgreSQLVectorStoreQueryProvider( - @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables, - @Nonnull ObjectMapper objectMapper) { - super( - dataSource, - collectionsTable, - prefixForCollectionTables, - buildSupportedKeyTypes(), - buildSupportedDataTypes(), - buildSupportedVectorTypes()); - this.collectionsTable = collectionsTable; - this.prefixForCollectionTables = prefixForCollectionTables; - this.objectMapper = objectMapper; - } - - private static Map, String> buildSupportedVectorTypes() { - HashMap, String> supportedVectorTypes = new HashMap<>(); - supportedVectorTypes.put(String.class, "TEXT"); - supportedVectorTypes.put(List.class, "VECTOR(%d)"); - supportedVectorTypes.put(Collection.class, "VECTOR(%d)"); - return supportedVectorTypes; - } - - private static Map, String> buildSupportedDataTypes() { - HashMap, String> supportedDataTypes = new HashMap<>(); - supportedDataTypes.put(String.class, "TEXT"); - supportedDataTypes.put(Integer.class, "INTEGER"); - supportedDataTypes.put(int.class, "INTEGER"); - supportedDataTypes.put(Long.class, "BIGINT"); - supportedDataTypes.put(long.class, "BIGINT"); - supportedDataTypes.put(Float.class, "REAL"); - supportedDataTypes.put(float.class, "REAL"); - supportedDataTypes.put(Double.class, "DOUBLE PRECISION"); - supportedDataTypes.put(double.class, "DOUBLE PRECISION"); - supportedDataTypes.put(Boolean.class, "BOOLEAN"); - supportedDataTypes.put(boolean.class, "BOOLEAN"); - supportedDataTypes.put(OffsetDateTime.class, "TIMESTAMPTZ"); - supportedDataTypes.put(List.class, "JSONB"); - return supportedDataTypes; - } - - private static HashMap, String> buildSupportedKeyTypes() { - HashMap, String> supportedKeyTypes = new HashMap<>(); - supportedKeyTypes.put(String.class, "VARCHAR(255)"); - return supportedKeyTypes; - } - - /** - * Creates a new builder. - * @return the builder - */ - public static PostgreSQLVectorStoreQueryProvider.Builder builder() { - return new PostgreSQLVectorStoreQueryProvider.Builder(); - } - - /** - * Prepares the vector store. - * Executes any necessary setup steps for the vector store. - * - * @throws SKException if an error occurs while preparing the vector store - */ - @Override - public void prepareVectorStore() { - super.prepareVectorStore(); - - // Create the vector extension - String pgVector = "CREATE EXTENSION IF NOT EXISTS vector"; - - try (Connection connection = dataSource.getConnection(); - PreparedStatement createPgVector = connection.prepareStatement(pgVector)) { - createPgVector.execute(); - } catch (SQLException e) { - throw new SKException("Failed to prepare vector store", e); - } - } - - private String getColumnNamesAndTypesForVectorFields( - List fields) { - return fields.stream() - .map(field -> { - String columnType; - if (field.getFieldType().equals(String.class)) { - columnType = supportedVectorTypes.get(String.class); - } else { - // Get the vector type and dimensions - columnType = String.format(supportedVectorTypes.get(field.getFieldType()), - field.getDimensions()); - } - return validateSQLidentifier(field.getEffectiveStorageName()) + " " + columnType; - }) - .collect(Collectors.joining(", ")); - } - - private String createIndexForVectorField(String collectionName, - VectorStoreRecordVectorField vectorField) { - PostgreSQLVectorIndexKind indexKind = PostgreSQLVectorIndexKind - .fromIndexKind(vectorField.getIndexKind()); - PostgreSQLVectorDistanceFunction distanceFunction = PostgreSQLVectorDistanceFunction - .fromDistanceFunction(vectorField.getDistanceFunction()); - - // If there is no approximate search index associated to the vector field, - // there is no need to create an index and pgvector performs exact nearest neighbor search. - if (indexKind == PostgreSQLVectorIndexKind.UNDEFINED) { - return null; - } - if (distanceFunction == PostgreSQLVectorDistanceFunction.UNDEFINED) { - throw new SKException( - "Distance function is required for vector field: " + vectorField.getName()); - } - - return formatQuery("CREATE INDEX IF NOT EXISTS %s ON %s USING %s (%s %s);", - getCollectionTableName(collectionName) + "_index", - getCollectionTableName(collectionName), - indexKind.getValue(), - vectorField.getEffectiveStorageName(), - distanceFunction.getValue()); - } - - /** - * Creates a collection. - * - * @param collectionName the collection name - * @param recordDefinition the record definition - * @throws SKException if an error occurs while creating the collection - */ - @Override - @SuppressFBWarnings(value = { - "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", - "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" - }) // SQL query is generated dynamically with valid identifiers - public void createCollection(String collectionName, - VectorStoreRecordDefinition recordDefinition) { - - List vectorFields = recordDefinition.getVectorFields(); - - try (Connection connection = dataSource.getConnection(); - Statement createTableAndIndexes = connection.createStatement()) { - - String createStorageTable = formatQuery("CREATE TABLE IF NOT EXISTS %s (" - + "%s VARCHAR(255) PRIMARY KEY, " - + "%s, " - + "%s);", - getCollectionTableName(collectionName), - getKeyColumnName(recordDefinition.getKeyField()), - getColumnNamesAndTypes(new ArrayList<>(recordDefinition.getDataFields()), - supportedDataTypes), - getColumnNamesAndTypesForVectorFields(recordDefinition.getVectorFields())); - - createTableAndIndexes.addBatch(createStorageTable); - for (VectorStoreRecordVectorField vectorField : vectorFields) { - String createVectorIndex = createIndexForVectorField(collectionName, vectorField); - - if (createVectorIndex != null) { - createTableAndIndexes.addBatch(createVectorIndex); - } - } - - createTableAndIndexes.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to create collection", e); - } - - String insertCollectionQuery = formatQuery("INSERT INTO %s (collectionId) VALUES (?)", - validateSQLidentifier(collectionsTable)); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement insert = connection.prepareStatement(insertCollectionQuery)) { - insert.setObject(1, collectionName); - insert.execute(); - } catch (SQLException e) { - throw new SKException("Failed to insert collection", e); - } - } - - private void setUpsertStatementValues(PreparedStatement statement, Object record, - List fields) { - JsonNode jsonNode = objectMapper.valueToTree(record); - - for (int i = 0; i < fields.size(); ++i) { - VectorStoreRecordField field = fields.get(i); - try { - JsonNode valueNode = jsonNode.get(field.getEffectiveStorageName()); - - if (field instanceof VectorStoreRecordVectorField) { - // Convert the vector field to a string - if (!field.getFieldType().equals(String.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } else if (field instanceof VectorStoreRecordDataField) { - // Convert List field to a string - if (field.getFieldType().equals(List.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } - - statement.setObject(i + 1, - objectMapper.convertValue(valueNode, field.getFieldType())); - } catch (SQLException | JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - private String getWildcardStringWithCast(List fields) { - return fields.stream() - .map(field -> { - String wildcard = "?"; - // Add casting for vector fields - if (field instanceof VectorStoreRecordVectorField) { - wildcard += "::vector"; - } - if (field instanceof VectorStoreRecordDataField) { - // Add casting for List fields - if (field.getFieldType().equals(List.class)) { - wildcard += "::jsonb"; - } - } - return wildcard; - }) - .collect(Collectors.joining(", ")); - } - - /** - * Upserts records into the collection. - * @param collectionName the collection name - * @param records the records to upsert - * @param recordDefinition the record definition - * @param options the upsert options - * @throws SKException if the upsert fails - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") // SQL query is generated dynamically with valid identifiers - public void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition recordDefinition, UpsertRecordOptions options) { - validateSQLidentifier(getCollectionTableName(collectionName)); - List fields = recordDefinition.getAllFields(); - - String onDuplicateKeyUpdate = fields.stream() - .filter(field -> !(field instanceof VectorStoreRecordKeyField)) // Exclude key fields - .map(field -> formatQuery("%s = EXCLUDED.%s", - validateSQLidentifier(field.getEffectiveStorageName()), - field.getEffectiveStorageName())) - .collect(Collectors.joining(", ")); - - String query = formatQuery( - "INSERT INTO %s (%s) VALUES (%s) ON CONFLICT (%s) DO UPDATE SET %s", - getCollectionTableName(collectionName), - getQueryColumnsFromFields(fields), - getWildcardStringWithCast(fields), - getKeyColumnName(recordDefinition.getKeyField()), - onDuplicateKeyUpdate); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (Object record : records) { - setUpsertStatementValues(statement, record, recordDefinition.getAllFields()); - statement.addBatch(); - } - - statement.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to upsert records", e); - } - } - - /** - * Vector search. - * Executes a vector search query and returns the results. - * The results are mapped to the specified record type using the provided mapper. - * The query is executed against the specified collection. - * - * @param the record type - * @param collectionName the collection name - * @param vector the vector to search with - * @param options the search options - * @param recordDefinition the record definition - * @param mapper the mapper, responsible for mapping the result set to the record type. - * @return the search results - */ - @Override - public VectorSearchResults search(String collectionName, - List vector, VectorSearchOptions options, - VectorStoreRecordDefinition recordDefinition, - VectorStoreRecordMapper mapper) { - if (recordDefinition.getVectorFields().isEmpty()) { - throw new SKException("No vector fields defined. Cannot perform vector search"); - } - - VectorStoreRecordVectorField firstVectorField = recordDefinition.getVectorFields() - .get(0); - if (options == null) { - options = VectorSearchOptions.createDefault(firstVectorField.getName()); - } - - VectorStoreRecordVectorField vectorField = options.getVectorFieldName() == null - ? firstVectorField - : (VectorStoreRecordVectorField) recordDefinition - .getField(options.getVectorFieldName()); - - PostgreSQLVectorIndexKind indexKind = PostgreSQLVectorIndexKind - .fromIndexKind(vectorField.getIndexKind()); - PostgreSQLVectorDistanceFunction distanceFunction = PostgreSQLVectorDistanceFunction - .fromDistanceFunction(vectorField.getDistanceFunction()); - - // If there is no approximate search index associated to the vector field, - // there is no index defined in the database and pgvector performs exact nearest neighbor search. - // If indexKind is defined, distance function is required. - if (indexKind != PostgreSQLVectorIndexKind.UNDEFINED - && distanceFunction == PostgreSQLVectorDistanceFunction.UNDEFINED) { - throw new SKException( - "Distance function is required for vector field: " + vectorField.getName()); - } - - String filter = getFilter(options.getVectorSearchFilter(), recordDefinition); - List parameters = getFilterParameters(options.getVectorSearchFilter()); - - String filterClause = filter.isEmpty() ? "" : "WHERE " + filter; - String searchQuery = formatQuery( - "SELECT %s, %s %s ?::vector AS score FROM %s %s ORDER BY score LIMIT ? OFFSET ?", - getQueryColumnsFromFields( - options.isIncludeVectors() ? recordDefinition.getAllFields() - : recordDefinition.getNonVectorFields()), - validateSQLidentifier(vectorField.getEffectiveStorageName()), - distanceFunction == null ? PostgreSQLVectorDistanceFunction.L2.getOperator() - : distanceFunction.getOperator(), - getCollectionTableName(collectionName), - filterClause); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(searchQuery)) { - int parameterIndex = 1; - - statement.setString(parameterIndex++, - objectMapper.writeValueAsString(vector)); - for (Object parameter : parameters) { - statement.setObject(parameterIndex++, parameter); - } - statement.setInt(parameterIndex++, options.getTop()); - statement.setInt(parameterIndex, options.getSkip()); - - List> records = new ArrayList<>(); - ResultSet resultSet = statement.executeQuery(); - - while (resultSet.next()) { - records.add(new VectorSearchResult<>( - mapper.mapStorageModelToRecord(resultSet, - new GetRecordOptions(options.isIncludeVectors())), - resultSet.getDouble("score"))); - } - - return new VectorSearchResults<>(records); - } catch (SQLException | JsonProcessingException e) { - throw new SKException("Failed to search records", e); - } - } - - /** - * Gets the filter parameters for the given vector search filter to associate with the filter string - * generated by the getFilter method. - * - * @param filter The filter to get the filter parameters for. - * @return The filter parameters. - */ - @Override - public List getFilterParameters(VectorSearchFilter filter) { - if (filter == null - || filter.getFilterClauses().isEmpty()) { - return Collections.emptyList(); - } - - return filter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - return equalToFilterClause.getValue(); - } else if (filterClause instanceof AnyTagEqualToFilterClause) { - AnyTagEqualToFilterClause anyTagEqualToFilterClause = (AnyTagEqualToFilterClause) filterClause; - return String.format("[\"%s\"]", anyTagEqualToFilterClause.getValue()); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.toList()); - } - - @Override - public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - String fieldName = JDBCVectorStoreQueryProvider - .validateSQLidentifier(filterClause.getFieldName()); - - return String.format("%s @> ?::jsonb", fieldName); - } - - @Override - public VectorStoreRecordMapper getVectorStoreRecordMapper( - Class recordClass, - VectorStoreRecordDefinition recordDefinition) { - return PostgreSQLVectorStoreRecordMapper.builder() - .withRecordClass(recordClass) - .withVectorStoreRecordDefinition(recordDefinition) - .build(); - } - - /** - * A builder for the PostgreSQLVectorStoreQueryProvider class. - */ - public static class Builder - extends JDBCVectorStoreQueryProvider.Builder { - private DataSource dataSource; - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - private ObjectMapper objectMapper = new ObjectMapper(); - - @SuppressFBWarnings("EI_EXPOSE_REP2") - public PostgreSQLVectorStoreQueryProvider.Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * @param collectionsTable the collections table name - * @return the builder - */ - public PostgreSQLVectorStoreQueryProvider.Builder withCollectionsTable( - String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public PostgreSQLVectorStoreQueryProvider.Builder withPrefixForCollectionTables( - String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public PostgreSQLVectorStoreQueryProvider.Builder withObjectMapper( - ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - public PostgreSQLVectorStoreQueryProvider build() { - if (dataSource == null) { - throw new SKException("DataSource is required"); - } - - return new PostgreSQLVectorStoreQueryProvider(dataSource, collectionsTable, - prefixForCollectionTables, objectMapper); - } - } -} diff --git a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreRecordMapper.java b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreRecordMapper.java deleted file mode 100644 index 11ced0e13..000000000 --- a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreRecordMapper.java +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.postgres; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.postgresql.util.PGobject; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; -import java.util.function.BiFunction; - -/** - * A mapper to convert between a record and a PostgreSQL storage model. - * - * @param the record type - */ -public class PostgreSQLVectorStoreRecordMapper - extends VectorStoreRecordMapper { - - /** - * Constructs a new instance of the VectorStoreRecordMapper. - * - * @param storageModelToRecordMapper the function to convert a storage model to a record - */ - protected PostgreSQLVectorStoreRecordMapper( - BiFunction storageModelToRecordMapper) { - super(null, storageModelToRecordMapper); - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * A builder for the PostgreSQLVectorStoreRecordMapper. - * - * @param the record type - */ - public static class Builder - implements SemanticKernelBuilder> { - private Class recordClass; - private VectorStoreRecordDefinition vectorStoreRecordDefinition; - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record definition. - * - * @param vectorStoreRecordDefinition the vector store record definition - * @return the builder - */ - public Builder withVectorStoreRecordDefinition( - VectorStoreRecordDefinition vectorStoreRecordDefinition) { - this.vectorStoreRecordDefinition = vectorStoreRecordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the {@link PostgreSQLVectorStoreRecordMapper}. - * - * @return the {@link PostgreSQLVectorStoreRecordMapper} - */ - public PostgreSQLVectorStoreRecordMapper build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - if (vectorStoreRecordDefinition == null) { - throw new SKException("vectorStoreRecordDefinition is required"); - } - - return new PostgreSQLVectorStoreRecordMapper<>( - (resultSet, options) -> { - try { - // Create an ObjectNode to hold the values - ObjectNode objectNode = objectMapper.createObjectNode(); - - // Select fields from the record definition. - List fields; - if (options != null && options.isIncludeVectors()) { - fields = vectorStoreRecordDefinition.getAllFields(); - } else { - fields = vectorStoreRecordDefinition.getNonVectorFields(); - } - - for (VectorStoreRecordField field : fields) { - Object value = resultSet.getObject(field.getEffectiveStorageName()); - Class fieldType = field.getFieldType(); - - if (field instanceof VectorStoreRecordVectorField) { - // If the vector field is other than String, deserialize it from the JSON string - if (!fieldType.equals(String.class)) { - // Deserialize the pgvector string to the vector type - value = objectMapper.readValue(((PGobject) value).getValue(), - fieldType); - } - } else if (field instanceof VectorStoreRecordDataField) { - // If the field is List, deserialize it from the JSON string - if (fieldType.equals(List.class)) { - value = objectMapper.readValue(((PGobject) value).getValue(), - fieldType); - } - } - - JsonNode genericNode = objectMapper.valueToTree(value); - objectNode.set(field.getEffectiveStorageName(), genericNode); - } - - return objectMapper.treeToValue(objectNode, recordClass); - } catch (SQLException | JsonProcessingException e) { - throw new SKException( - "Failure to serialize object, by default the JDBC connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }); - } - } -} diff --git a/data/semantickernel-data-redis/pom.xml b/data/semantickernel-data-redis/pom.xml deleted file mode 100644 index de2f60ee5..000000000 --- a/data/semantickernel-data-redis/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - semantickernel-data-redis - Semantic Kernel Redis connector - Provides a Redis connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - - org.slf4j - slf4j-api - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.jknack - handlebars - - - com.google.code.findbugs - jsr305 - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.apache.commons - commons-text - - - - redis.clients - jedis - - - - \ No newline at end of file diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollection.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollection.java deleted file mode 100644 index 74dd1213b..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollection.java +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.lang3.tuple.Pair; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Response; -import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.jedis.search.FTSearchParams; -import redis.clients.jedis.search.IndexDefinition; -import redis.clients.jedis.search.IndexOptions; -import redis.clients.jedis.search.Schema; -import redis.clients.jedis.search.SearchResult; - -import javax.annotation.Nonnull; -import java.nio.charset.StandardCharsets; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * RedisHashSetVectorStoreRecordCollection is a class that represents a - * collection of records stored in Redis using the Hash Set data structure. - * @param The record type. - */ -public class RedisHashSetVectorStoreRecordCollection - implements VectorStoreRecordCollection, - VectorizedSearch { - - private static final HashSet> supportedKeyTypes = new HashSet<>( - Collections.singletonList( - String.class)); - - private static final HashSet> supportedVectorTypes = new HashSet<>( - Arrays.asList( - List.class, - Collection.class)); - - private final JedisPooled client; - private final String collectionName; - private final RedisHashSetVectorStoreRecordCollectionOptions options; - private final VectorStoreRecordMapper>> vectorStoreRecordMapper; - private final VectorStoreRecordDefinition recordDefinition; - private final byte[][] dataFields; - private final ObjectMapper objectMapper; - - /** - * Creates a new instance of the RedisVectorRecordStore. - * - * @param client The Redis client. - * @param collectionName The name of the collection. - * @param options The options for the store. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public RedisHashSetVectorStoreRecordCollection( - @Nonnull JedisPooled client, - @Nonnull String collectionName, - @Nonnull RedisHashSetVectorStoreRecordCollectionOptions options) { - this.client = client; - this.collectionName = collectionName; - this.options = options; - - // If record definition is not provided, create one from the record class - if (options.getRecordDefinition() == null) { - this.recordDefinition = VectorStoreRecordDefinition.fromRecordClass( - options.getRecordClass()); - } else { - this.recordDefinition = options.getRecordDefinition(); - } - - // Validate supported types - VectorStoreRecordDefinition.validateSupportedTypes( - Collections.singletonList(recordDefinition.getKeyField()), - supportedKeyTypes); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getVectorFields()), - supportedVectorTypes); - - // If mapper is not provided, set a default one - objectMapper = options.getObjectMapper() != null ? options.getObjectMapper() - : new ObjectMapper(); - - // If mapper is not provided, set a default one - if (options.getVectorStoreRecordMapper() == null) { - vectorStoreRecordMapper = new RedisHashSetVectorStoreRecordMapper.Builder() - .withRecordClass(options.getRecordClass()) - .withVectorStoreRecordDefinition(recordDefinition) - .withObjectMapper(objectMapper) - .build(); - } else { - vectorStoreRecordMapper = options.getVectorStoreRecordMapper(); - } - - // Creates a list of paths to retrieve from Redis when no vectors are requested - this.dataFields = new byte[recordDefinition.getDataFields().size()][]; - for (int i = 0; i < recordDefinition.getDataFields().size(); i++) { - this.dataFields[i] = stringToBytes( - recordDefinition.getDataFields().get(i).getEffectiveStorageName()); - } - } - - /** - * Gets the name of the collection. - * - * @return The name of the collection. - */ - @Override - public String getCollectionName() { - return collectionName; - } - - /** - * Checks if the collection exists in the store. - * - * @return A Mono emitting a boolean indicating if the collection exists. - */ - @Override - public Mono collectionExistsAsync() { - return Mono.fromCallable(() -> { - try { - Map info = this.client.ftInfo(collectionName); - return info != null && !info.isEmpty(); - } catch (Exception e) { - if (!(e instanceof JedisDataException)) { - throw e; - } - return false; - } - }).subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Creates the collection in the store. - * - * @return A Mono representing the completion of the creation operation. - */ - @Override - public Mono> createCollectionAsync() { - return Mono.fromRunnable(() -> { - Schema schema = RedisVectorStoreCollectionCreateMapping - .mapToSchema(recordDefinition.getAllFields(), RedisStorageType.HASH_SET); - - IndexDefinition indexDefinition = new IndexDefinition(IndexDefinition.Type.HASH) - .setPrefixes(collectionName + ":"); - - client.ftCreate( - collectionName, - IndexOptions.defaultOptions().setDefinition(indexDefinition), - schema); - }) - .subscribeOn(Schedulers.boundedElastic()) - .then(Mono.just(this)); - } - - /** - * Creates the collection in the store if it does not exist. - * - * @return A Mono representing the completion of the creation operation. - */ - @Override - public Mono> createCollectionIfNotExistsAsync() { - return collectionExistsAsync().flatMap(exists -> { - if (!exists) { - return createCollectionAsync(); - } - - return Mono.just(this); - }); - } - - /** - * Deletes the collection from the store. - * - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteCollectionAsync() { - return Mono.fromRunnable(() -> client.ftDropIndex(collectionName)) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - private String prefixKeyIfNeeded(String key, String collectionName) { - return options.isPrefixCollectionName() ? collectionName + ":" + key : key; - } - - private String removeKeyPrefixIfNeeded(String key, String collectionName) { - if (options.isPrefixCollectionName() && key.startsWith(collectionName + ":")) { - return key.substring(collectionName.length() + 1); - } - return key; - } - - static byte[] stringToBytes(String value) { - return value.getBytes(StandardCharsets.UTF_8); - } - - private Map addDataFieldNames(List result) { - Map dataFields = new HashMap<>(); - for (int i = 0; i < result.size(); i++) { - if (result.get(i) == null) { - continue; - } - dataFields.put(this.dataFields[i], result.get(i)); - } - return dataFields; - } - - /** - * Gets a record from the store. - * - * @param key The key of the record to get. - * @param options The options for getting the record. - * @return A Mono emitting the record. - */ - @Override - public Mono getAsync(String key, GetRecordOptions options) { - return getBatchAsync(Collections.singletonList(key), options) - .mapNotNull(records -> { - if (records.isEmpty()) { - return null; - } - - return records.get(0); - }); - } - - /** - * Gets a batch of records from the store. - * - * @param keys The keys of the records to get. - * @param options The options for getting the records. - * @return A Mono emitting a list of records. - */ - @Override - public Mono> getBatchAsync(List keys, - GetRecordOptions options) { - Pipeline pipeline = client.pipelined(); - List>> responses = new ArrayList<>(keys.size()); - keys.forEach(key -> { - String redisKey = prefixKeyIfNeeded(key, collectionName); - - if (options != null && options.isIncludeVectors()) { - // Returns Map with the fields and values - responses - .add(new AbstractMap.SimpleEntry<>(key, - pipeline.hgetAll(stringToBytes(redisKey)))); - } else { - // Returns List with the values of the fields - responses - .add(new AbstractMap.SimpleEntry<>(key, - pipeline.hmget(stringToBytes(redisKey), dataFields))); - } - }); - - return Mono.defer(() -> { - pipeline.sync(); - - try { - return Mono.just(responses.stream() - .map(entry -> { - if (options != null && options.isIncludeVectors()) { - // Results directly in a Map - return this.vectorStoreRecordMapper - .mapStorageModelToRecord( - new AbstractMap.SimpleEntry<>(entry.getKey(), - (Map) entry.getValue().get()), - options); - } - - // Results in a List with the values of the fields - return this.vectorStoreRecordMapper - .mapStorageModelToRecord( - new AbstractMap.SimpleEntry<>(entry.getKey(), - addDataFieldNames((List) entry.getValue().get())), - options); - }) - .collect(Collectors.toList())); - } catch (Exception e) { - return Mono.error(e); - } - }).subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Inserts or updates a record in the store. - * - * @param data The record to upsert. - * @param options The options for upserting the record. - * @return A Mono emitting the key of the upserted record. - */ - @Override - public Mono upsertAsync(Record data, UpsertRecordOptions options) { - Map.Entry> redisObject = this.vectorStoreRecordMapper - .mapRecordToStorageModel(data); - String redisKey = prefixKeyIfNeeded(redisObject.getKey(), collectionName); - - return Mono.fromRunnable(() -> client.hset(stringToBytes(redisKey), redisObject.getValue())) - .subscribeOn(Schedulers.boundedElastic()) - .thenReturn(redisObject.getKey()); - } - - /** - * Inserts or updates a batch of records in the store. - * - * @param data The records to upsert. - * @param options The options for upserting the records. - * @return A Mono emitting a collection of keys of the upserted records. - */ - @Override - public Mono> upsertBatchAsync(List data, UpsertRecordOptions options) { - Pipeline pipeline = client.pipelined(); - List keys = new ArrayList<>(data.size()); - - data.forEach(record -> { - Map.Entry> redisObject = this.vectorStoreRecordMapper - .mapRecordToStorageModel(record); - String redisKey = prefixKeyIfNeeded(redisObject.getKey(), collectionName); - - keys.add(redisObject.getKey()); - pipeline.hset(stringToBytes(redisKey), redisObject.getValue()); - }); - - return Mono.fromRunnable(pipeline::sync) - .subscribeOn(Schedulers.boundedElastic()) - .thenReturn(keys); - } - - /** - * Deletes a record from the store. - * - * @param key The key of the record to delete. - * @param options The options for deleting the record. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteAsync(String key, DeleteRecordOptions options) { - String redisKey = prefixKeyIfNeeded(key, collectionName); - - return Mono.fromRunnable(() -> client.del(redisKey)) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - /** - * Deletes a batch of records from the store. - * - * @param strings The keys of the records to delete. - * @param options The options for deleting the records. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteBatchAsync(List strings, DeleteRecordOptions options) { - Pipeline pipeline = client.pipelined(); - strings.forEach(key -> { - String redisKey = prefixKeyIfNeeded(key, collectionName); - pipeline.del(redisKey); - }); - - return Mono.fromRunnable(pipeline::sync) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param options The options to use for the search. - * @return A list of search results. - */ - @Override - public Mono> searchAsync(List vector, - VectorSearchOptions options) { - if (recordDefinition.getVectorFields().isEmpty()) { - return Mono - .error(new SKException("No vector fields defined. Cannot perform vector search")); - } - - return createCollectionIfNotExistsAsync().flatMap(collection -> Mono.fromCallable(() -> { - Pair ftSearchParams = RedisVectorStoreCollectionSearchMapping - .getInstance() - .buildQuery(vector, options, recordDefinition, RedisStorageType.HASH_SET); - - SearchResult searchResult = client.ftSearch(collectionName, ftSearchParams.getLeft(), - ftSearchParams.getRight()); - - List> results = searchResult.getDocuments().stream() - .map(doc -> { - String key = removeKeyPrefixIfNeeded(doc.getId(), collectionName); - double score = 0; - - // Convert from Map to Map - Map storage = new HashMap<>(); - for (Map.Entry entry : doc.getProperties()) { - // Data and vector fields are returned as byte[] - if (entry.getValue() instanceof byte[]) { - storage.put(stringToBytes(entry.getKey()), - (byte[]) entry.getValue()); - } - // Score is returned as a string - else if (entry.getKey().equals( - RedisVectorStoreCollectionSearchMapping.VECTOR_SCORE_FIELD)) { - // Score is stored as a string in one of the fields - score = Double.parseDouble((String) entry.getValue()); - } - } - - Record record = this.vectorStoreRecordMapper - .mapStorageModelToRecord( - new AbstractMap.SimpleEntry<>(key, storage), - new GetRecordOptions( - options != null && options.isIncludeVectors())); - - return new VectorSearchResult<>(record, score); - }) - .collect(Collectors.toList()); - - return new VectorSearchResults<>(results); - }).subscribeOn(Schedulers.boundedElastic())); - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollectionOptions.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollectionOptions.java deleted file mode 100644 index c4730d2ad..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Options for a Redis hash set vector store record collection. - * @param the record type - */ -public class RedisHashSetVectorStoreRecordCollectionOptions - implements VectorStoreRecordCollectionOptions { - private final Class recordClass; - @Nullable - private final VectorStoreRecordMapper>> vectorStoreRecordMapper; - @Nullable - private final VectorStoreRecordDefinition recordDefinition; - private final boolean prefixCollectionName; - @Nullable - private final ObjectMapper objectMapper; - - private RedisHashSetVectorStoreRecordCollectionOptions( - @Nonnull Class recordClass, - @Nullable VectorStoreRecordMapper>> vectorStoreRecordMapper, - @Nullable VectorStoreRecordDefinition recordDefinition, - boolean prefixCollectionName, - @Nullable ObjectMapper objectMapper) { - this.recordClass = recordClass; - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - this.recordDefinition = recordDefinition; - this.prefixCollectionName = prefixCollectionName; - this.objectMapper = objectMapper; - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Gets the key class. - * - * @return the key class - */ - @Override - public Class getKeyClass() { - return String.class; - } - - /** - * Gets the record class. - * - * @return the record class - */ - public Class getRecordClass() { - return recordClass; - } - - /** - * Gets the record definition. - * - * @return the record definition - */ - @Nullable - public VectorStoreRecordDefinition getRecordDefinition() { - return recordDefinition; - } - - /** - * Gets the vector store record mapper. - * - * @return the vector store record mapper - */ - @Nullable - public VectorStoreRecordMapper>> getVectorStoreRecordMapper() { - return vectorStoreRecordMapper; - } - - /** - * Gets whether to prefix the collection name to the redis key. - * - * @return whether to prefix the collection name to the redis key - */ - public boolean isPrefixCollectionName() { - return prefixCollectionName; - } - - /** - * Gets the object mapper. - * - * @return the object mapper - */ - @Nullable - ObjectMapper getObjectMapper() { - return objectMapper; - } - - /** - * Builder for {@link RedisHashSetVectorStoreRecordCollectionOptions}. - * - * @param the record type - */ - public static class Builder { - @Nullable - private VectorStoreRecordMapper>> vectorStoreRecordMapper; - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - private boolean prefixCollectionName = true; - @Nullable - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record mapper. - * - * @param vectorStoreRecordMapper the vector store record mapper - * @return the builder - */ - public Builder withVectorStoreRecordMapper( - VectorStoreRecordMapper>> vectorStoreRecordMapper) { - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - return this; - } - - /** - * Sets the record definition. - * - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets whether to prefix the collection name to the redis key. - * Default is true. - * - * @param prefixCollectionName whether to prefix the collection name to the redis key - * @return the builder - */ - public Builder withPrefixCollectionName(boolean prefixCollectionName) { - this.prefixCollectionName = prefixCollectionName; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the options. - * - * @return the options - */ - public RedisHashSetVectorStoreRecordCollectionOptions build() { - if (recordClass == null) { - throw new SKException("recordClass must be provided"); - } - - return new RedisHashSetVectorStoreRecordCollectionOptions<>( - recordClass, - vectorStoreRecordMapper, - recordDefinition, - prefixCollectionName, - objectMapper); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordMapper.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordMapper.java deleted file mode 100644 index 5ba97dfea..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisHashSetVectorStoreRecordMapper.java +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static com.microsoft.semantickernel.data.redis.RedisHashSetVectorStoreRecordCollection.stringToBytes; - -/** - * A mapper to convert between a record and a Redis hash set storage model. - * @param the record type - */ -public class RedisHashSetVectorStoreRecordMapper - extends VectorStoreRecordMapper>> { - - private RedisHashSetVectorStoreRecordMapper( - Function>> toStorageModelMapper, - BiFunction>, GetRecordOptions, Record> toRecordMapper) { - super(toStorageModelMapper, toRecordMapper); - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Creates a new builder. - * - * @param the record type - */ - public static class Builder - implements SemanticKernelBuilder> { - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - @Nullable - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record definition. - * - * @param recordDefinition the vector store record definition - * @return the builder - */ - public Builder withVectorStoreRecordDefinition( - VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the {@link RedisHashSetVectorStoreRecordMapper}. - * - * @return the {@link RedisHashSetVectorStoreRecordMapper} - */ - @Override - public RedisHashSetVectorStoreRecordMapper build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - if (recordDefinition == null) { - throw new SKException("vectorStoreRecordDefinition is required"); - } - - return new RedisHashSetVectorStoreRecordMapper<>(record -> { - try { - ObjectNode jsonNode = objectMapper.valueToTree(record); - - String key = jsonNode - .get(recordDefinition.getKeyField().getEffectiveStorageName()).asText(); - jsonNode.remove(recordDefinition.getKeyField().getEffectiveStorageName()); - - Map storage = new HashMap<>(); - for (VectorStoreRecordDataField field : recordDefinition.getDataFields()) { - JsonNode value = jsonNode.get(field.getEffectiveStorageName()); - if (value != null) { - storage.put( - stringToBytes(field.getEffectiveStorageName()), - objectMapper.writeValueAsBytes(value)); - } - } - for (VectorStoreRecordVectorField field : recordDefinition.getVectorFields()) { - ArrayNode value = (ArrayNode) jsonNode.get(field.getEffectiveStorageName()); - List vector = objectMapper.convertValue(value, List.class); - if (value != null) { - storage.put( - stringToBytes(field.getEffectiveStorageName()), - RedisVectorStoreCollectionSearchMapping - .convertListToByteArray(vector)); - } - } - - return new AbstractMap.SimpleEntry<>(key, storage); - } catch (Exception e) { - throw new SKException( - "Failure to serialize object, by default the Redis connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }, (storageModel, options) -> { - try { - // Empty map means no record found - if (storageModel.getValue() == null || storageModel.getValue().isEmpty()) { - return null; - } - - ObjectNode jsonNode = objectMapper.createObjectNode(); - jsonNode.set(recordDefinition.getKeyField().getEffectiveStorageName(), - objectMapper.valueToTree(storageModel.getKey())); - - // byte[] as key is not useful, convert to String - Map storage = new HashMap<>(); - storageModel.getValue() - .forEach((k, v) -> storage.put(new String(k, StandardCharsets.UTF_8), v)); - - for (VectorStoreRecordDataField field : recordDefinition.getDataFields()) { - byte[] value = storage.get(field.getEffectiveStorageName()); - if (value != null) { - jsonNode.set(field.getEffectiveStorageName(), - objectMapper.valueToTree( - objectMapper.readValue(value, field.getFieldType()))); - } - } - if (options != null && options.isIncludeVectors()) { - for (VectorStoreRecordVectorField field : recordDefinition - .getVectorFields()) { - byte[] value = storage.get(field.getEffectiveStorageName()); - if (value != null) { - jsonNode.set(field.getEffectiveStorageName(), - objectMapper.valueToTree(RedisVectorStoreCollectionSearchMapping - .convertByteArrayToList(value))); - } - } - } - - return objectMapper.convertValue(jsonNode, recordClass); - } catch (JsonProcessingException e) { - throw new SKException( - "Failure to deserialize object, by default the Redis connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollection.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollection.java deleted file mode 100644 index 50db6bd9b..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollection.java +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.AbstractMap.SimpleEntry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; - -import org.apache.commons.lang3.tuple.Pair; -import org.json.JSONArray; -import org.json.JSONObject; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Response; -import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.jedis.json.Path2; -import redis.clients.jedis.search.FTSearchParams; -import redis.clients.jedis.search.IndexDefinition; -import redis.clients.jedis.search.IndexOptions; -import redis.clients.jedis.search.Schema; -import redis.clients.jedis.search.SearchResult; - -/** - * Represents a Redis vector store record collection. - * - * @param The type of record in the collection. - */ -public class RedisJsonVectorStoreRecordCollection - implements VectorStoreRecordCollection, - VectorizedSearch { - - private static final HashSet> supportedKeyTypes = new HashSet<>( - Collections.singletonList( - String.class)); - - private static final HashSet> supportedVectorTypes = new HashSet<>( - Arrays.asList( - List.class, - Collection.class)); - - private final JedisPooled client; - private final String collectionName; - private final RedisJsonVectorStoreRecordCollectionOptions options; - private final VectorStoreRecordMapper> vectorStoreRecordMapper; - private final VectorStoreRecordDefinition recordDefinition; - private final Path2[] dataFields; - private final ObjectMapper objectMapper; - - /** - * Creates a new instance of the RedisVectorRecordStore. - * - * @param client The Redis client. - * @param collectionName The name of the collection. - * @param options The options for the store. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public RedisJsonVectorStoreRecordCollection( - @Nonnull JedisPooled client, - @Nonnull String collectionName, - @Nonnull RedisJsonVectorStoreRecordCollectionOptions options) { - this.client = client; - this.collectionName = collectionName; - this.options = options; - - // If record definition is not provided, create one from the record class - if (options.getRecordDefinition() == null) { - this.recordDefinition = VectorStoreRecordDefinition.fromRecordClass( - options.getRecordClass()); - } else { - this.recordDefinition = options.getRecordDefinition(); - } - - // Validate supported types - VectorStoreRecordDefinition.validateSupportedTypes( - Collections.singletonList(recordDefinition.getKeyField()), - supportedKeyTypes); - VectorStoreRecordDefinition.validateSupportedTypes( - new ArrayList<>(recordDefinition.getVectorFields()), - supportedVectorTypes); - - // If object mapper is not provided, set a default one - this.objectMapper = options.getObjectMapper() != null ? options.getObjectMapper() - : new ObjectMapper(); - - // If mapper is not provided, set a default one - if (options.getVectorStoreRecordMapper() == null) { - vectorStoreRecordMapper = new RedisJsonVectorStoreRecordMapper.Builder() - .withRecordClass(options.getRecordClass()) - .withRecordDefinition(recordDefinition) - .withObjectMapper(objectMapper) - .build(); - } else { - vectorStoreRecordMapper = options.getVectorStoreRecordMapper(); - } - - // Creates a list of paths to retrieve from Redis when no vectors are requested - // Paths are in the format of $.field - this.dataFields = recordDefinition.getDataFields().stream() - .map(VectorStoreRecordDataField::getEffectiveStorageName) - .map(Path2::new) - .toArray(Path2[]::new); - } - - /** - * Gets the name of the collection. - * - * @return The name of the collection. - */ - @Override - public String getCollectionName() { - return collectionName; - } - - /** - * Checks if the collection exists in the store. - * - * @return A Mono emitting a boolean indicating if the collection exists. - */ - @Override - public Mono collectionExistsAsync() { - return Mono.fromCallable(() -> { - try { - Map info = this.client.ftInfo(collectionName); - return info != null && !info.isEmpty(); - } catch (Exception e) { - if (!(e instanceof JedisDataException)) { - throw e; - } - return false; - } - }).subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Creates the collection in the store. - * - * @return A Mono representing the completion of the creation operation. - */ - @Override - public Mono> createCollectionAsync() { - return Mono.fromRunnable(() -> { - Schema schema = RedisVectorStoreCollectionCreateMapping - .mapToSchema(recordDefinition.getAllFields(), RedisStorageType.JSON); - - IndexDefinition indexDefinition = new IndexDefinition(IndexDefinition.Type.JSON) - .setPrefixes(collectionName + ":"); - - client.ftCreate( - collectionName, - IndexOptions.defaultOptions().setDefinition(indexDefinition), - schema); - }) - .subscribeOn(Schedulers.boundedElastic()) - .then(Mono.just(this)); - } - - @Override - public Mono> createCollectionIfNotExistsAsync() { - return collectionExistsAsync().flatMap(exists -> { - if (!exists) { - return createCollectionAsync(); - } - - return Mono.just(this); - }); - } - - /** - * Deletes the collection from the store. - * - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteCollectionAsync() { - return Mono.fromRunnable(() -> client.ftDropIndex(collectionName)) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - private String prefixKeyIfNeeded(String key, String collectionName) { - return options.isPrefixCollectionName() ? collectionName + ":" + key : key; - } - - private String removeKeyPrefixIfNeeded(String key, String collectionName) { - if (options.isPrefixCollectionName() && key.startsWith(collectionName + ":")) { - return key.substring(collectionName.length() + 1); - } - return key; - } - - private JsonNode removeRedisPathPrefix(JSONObject object) { - ObjectNode noPathPrefix = objectMapper.createObjectNode(); - object.keySet().forEach(key -> { - String newKey = key; - if (key.startsWith("$.")) { - newKey = key.substring(2); - } - - Object value = ((JSONArray) object.get(key)).get(0); - noPathPrefix.set(newKey, objectMapper.valueToTree(value)); - }); - - return noPathPrefix; - } - - /** - * Gets a record from the store. - * - * @param key The key of the record to get. - * @param options The options for getting the record. - * @return A Mono emitting the record. - */ - @Override - public Mono getAsync(String key, GetRecordOptions options) { - String redisKey = prefixKeyIfNeeded(key, collectionName); - - return Mono.defer(() -> { - try { - Object value; - if (options != null && options.isIncludeVectors()) { - value = client.jsonGet(redisKey); - } else { - value = client.jsonGet(redisKey, dataFields); - } - - if (value == null) { - return Mono.empty(); - } - - JsonNode jsonNode; - if (options != null && options.isIncludeVectors()) { - jsonNode = objectMapper.valueToTree(value); - } else { - // Remove the $. prefix from every key in the JSON object - jsonNode = removeRedisPathPrefix((JSONObject) value); - } - - return Mono.just(this.vectorStoreRecordMapper - .mapStorageModelToRecord(new SimpleEntry<>(key, jsonNode), options)); - } catch (Exception e) { - return Mono.error(e); - } - }).subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Gets a batch of records from the store. - * - * @param keys The keys of the records to get. - * @param options The options for getting the records. - * @return A Mono emitting a list of records. - */ - @Override - public Mono> getBatchAsync(List keys, - GetRecordOptions options) { - Pipeline pipeline = client.pipelined(); - List>> responses = new ArrayList<>(keys.size()); - keys.forEach(key -> { - String redisKey = prefixKeyIfNeeded(key, collectionName); - - if (options != null && options.isIncludeVectors()) { - responses.add(new SimpleEntry<>(key, pipeline.jsonGet(redisKey))); - } else { - responses.add(new SimpleEntry<>(key, pipeline.jsonGet(redisKey, dataFields))); - } - }); - - return Mono.defer(() -> { - pipeline.sync(); - - try { - return Mono.just(responses.stream() - .map(entry -> { - Object value = entry.getValue().get(); - if (value == null) { - return null; - } - - JsonNode jsonNode; - if (options != null && options.isIncludeVectors()) { - jsonNode = objectMapper.valueToTree(value); - } else { - jsonNode = removeRedisPathPrefix((JSONObject) value); - } - return this.vectorStoreRecordMapper - .mapStorageModelToRecord(new SimpleEntry<>(entry.getKey(), jsonNode), - options); - }) - .collect(Collectors.toList())); - } catch (Exception e) { - return Mono.error(e); - } - }).subscribeOn(Schedulers.boundedElastic()); - } - - /** - * Inserts or updates a record in the store. - * - * @param data The record to upsert. - * @param options The options for upserting the record. - * @return A Mono emitting the key of the upserted record. - */ - @Override - public Mono upsertAsync(Record data, UpsertRecordOptions options) { - Entry redisObject = this.vectorStoreRecordMapper - .mapRecordToStorageModel(data); - String redisKey = prefixKeyIfNeeded(redisObject.getKey(), collectionName); - - return Mono.fromRunnable(() -> client.jsonSet(redisKey, redisObject.getValue())) - .subscribeOn(Schedulers.boundedElastic()) - .thenReturn(redisObject.getKey()); - } - - /** - * Inserts or updates a batch of records in the store. - * - * @param data The records to upsert. - * @param options The options for upserting the records. - * @return A Mono emitting a collection of keys of the upserted records. - */ - @Override - public Mono> upsertBatchAsync(List data, UpsertRecordOptions options) { - Pipeline pipeline = client.pipelined(); - List keys = new ArrayList<>(data.size()); - - data.forEach(record -> { - Entry redisObject = this.vectorStoreRecordMapper - .mapRecordToStorageModel(record); - String redisKey = prefixKeyIfNeeded(redisObject.getKey(), collectionName); - - keys.add(redisObject.getKey()); - pipeline.jsonSet(redisKey, redisObject.getValue()); - }); - - return Mono.fromRunnable(pipeline::sync) - .subscribeOn(Schedulers.boundedElastic()) - .thenReturn(keys); - } - - /** - * Deletes a record from the store. - * - * @param key The key of the record to delete. - * @param options The options for deleting the record. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteAsync(String key, DeleteRecordOptions options) { - String redisKey = prefixKeyIfNeeded(key, collectionName); - - return Mono.fromRunnable(() -> client.del(redisKey)) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - /** - * Deletes a batch of records from the store. - * - * @param strings The keys of the records to delete. - * @param options The options for deleting the records. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteBatchAsync(List strings, DeleteRecordOptions options) { - Pipeline pipeline = client.pipelined(); - strings.forEach(key -> { - String redisKey = prefixKeyIfNeeded(key, collectionName); - pipeline.del(redisKey); - }); - - return Mono.fromRunnable(pipeline::sync) - .subscribeOn(Schedulers.boundedElastic()) - .then(); - } - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param options The options to use for the search. - * @return The search results. - */ - @Override - public Mono> searchAsync(List vector, - VectorSearchOptions options) { - if (recordDefinition.getVectorFields().isEmpty()) { - return Mono - .error(new SKException("No vector fields defined. Cannot perform vector search")); - } - - return createCollectionIfNotExistsAsync().flatMap(collection -> Mono.fromCallable(() -> { - Pair ftSearchParams = RedisVectorStoreCollectionSearchMapping - .getInstance().buildQuery(vector, options, recordDefinition, RedisStorageType.JSON); - - SearchResult searchResult = client.ftSearch(collectionName, - ftSearchParams.getLeft(), ftSearchParams.getRight()); - - List> results = searchResult.getDocuments().stream() - .map(doc -> { - Map properties = new HashMap<>(); - for (Map.Entry entry : doc.getProperties()) { - properties.put(entry.getKey(), entry.getValue()); - } - - String key = removeKeyPrefixIfNeeded(doc.getId(), collectionName); - String value = (String) properties.get("$"); - double score = Double.parseDouble((String) properties - .get(RedisVectorStoreCollectionSearchMapping.VECTOR_SCORE_FIELD)); - - try { - JsonNode jsonNode = objectMapper.readTree(value); - Record record = this.vectorStoreRecordMapper - .mapStorageModelToRecord(new SimpleEntry<>(key, jsonNode), - new GetRecordOptions( - options != null && options.isIncludeVectors())); - - return new VectorSearchResult<>(record, score); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }).collect(Collectors.toList()); - - return new VectorSearchResults<>(results); - }).subscribeOn(Schedulers.boundedElastic())); - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollectionOptions.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollectionOptions.java deleted file mode 100644 index 0ba8b9018..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Map.Entry; - -/** - * Options for a Redis vector store record collection. - * - * @param the record type - */ -public class RedisJsonVectorStoreRecordCollectionOptions - implements VectorStoreRecordCollectionOptions { - private final Class recordClass; - @Nullable - private final VectorStoreRecordMapper> vectorStoreRecordMapper; - @Nullable - private final VectorStoreRecordDefinition recordDefinition; - private final boolean prefixCollectionName; - private final ObjectMapper objectMapper; - - private RedisJsonVectorStoreRecordCollectionOptions( - @Nonnull Class recordClass, - @Nullable VectorStoreRecordMapper> vectorStoreRecordMapper, - @Nullable VectorStoreRecordDefinition recordDefinition, - boolean prefixCollectionName, - @Nullable ObjectMapper objectMapper) { - this.recordClass = recordClass; - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - this.recordDefinition = recordDefinition; - this.prefixCollectionName = prefixCollectionName; - this.objectMapper = objectMapper; - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Gets the key class. - * - * @return the key class - */ - @Override - public Class getKeyClass() { - return String.class; - } - - /** - * Gets the record class. - * - * @return the record class - */ - public Class getRecordClass() { - return recordClass; - } - - /** - * Gets the record definition. - * - * @return the record definition - */ - @Nullable - public VectorStoreRecordDefinition getRecordDefinition() { - return recordDefinition; - } - - /** - * Gets the vector store record mapper. - * - * @return the vector store record mapper - */ - @Nullable - public VectorStoreRecordMapper> getVectorStoreRecordMapper() { - return vectorStoreRecordMapper; - } - - /** - * Gets whether to prefix the collection name to the redis key. - * - * @return whether to prefix the collection name to the redis key - */ - public boolean isPrefixCollectionName() { - return prefixCollectionName; - } - - /** - * Gets the object mapper. - * - * @return the object mapper - */ - ObjectMapper getObjectMapper() { - return objectMapper; - } - - /** - * Builder for {@link RedisJsonVectorStoreRecordCollectionOptions}. - * - * @param the record type - */ - public static class Builder { - @Nullable - private VectorStoreRecordMapper> vectorStoreRecordMapper; - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - private boolean prefixCollectionName = true; - @Nullable - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the vector store record mapper. - * - * @param vectorStoreRecordMapper the vector store record mapper - * @return the builder - */ - public Builder withVectorStoreRecordMapper( - VectorStoreRecordMapper> vectorStoreRecordMapper) { - this.vectorStoreRecordMapper = vectorStoreRecordMapper; - return this; - } - - /** - * Sets the record definition. - * - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets whether the collection name should be prefixed to the key names before reading or writing to the Redis store. Default is true. - *

- * For a record to be indexed by a specific Redis index, the key name must be prefixed with the matching prefix configured on the Redis index. - * You can either pass in keys that are already prefixed, or set this option to true to have the collection name prefixed to the key names automatically. - * @param prefixCollectionName whether to prefix the collection name to the key - * @return the builder - */ - public Builder withPrefixCollectionName(boolean prefixCollectionName) { - this.prefixCollectionName = prefixCollectionName; - return this; - } - - /** - * Sets the object mapper to use for serialization and deserialization. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the options. - * - * @return the options - */ - public RedisJsonVectorStoreRecordCollectionOptions build() { - if (recordClass == null) { - throw new SKException("recordClass must be provided"); - } - - return new RedisJsonVectorStoreRecordCollectionOptions<>( - recordClass, - vectorStoreRecordMapper, - recordDefinition, - prefixCollectionName, - objectMapper); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordMapper.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordMapper.java deleted file mode 100644 index f0de10bb2..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisJsonVectorStoreRecordMapper.java +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordMapper; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.util.AbstractMap; -import java.util.Map.Entry; -import java.util.function.BiFunction; -import java.util.function.Function; -import javax.annotation.Nullable; - -/** - * A mapper to convert between a record and a Redis JSON storage model. - * @param the record type - */ -public class RedisJsonVectorStoreRecordMapper - extends VectorStoreRecordMapper> { - - private RedisJsonVectorStoreRecordMapper( - Function> toStorageModelMapper, - BiFunction, GetRecordOptions, Record> toRecordMapper) { - super(toStorageModelMapper, toRecordMapper); - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Creates a new builder. - * - * @param the record type - */ - public static class Builder - implements SemanticKernelBuilder> { - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the record definition. - * - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the {@link RedisJsonVectorStoreRecordMapper}. - * - * @return the {@link RedisJsonVectorStoreRecordMapper} - */ - @Override - public RedisJsonVectorStoreRecordMapper build() { - if (recordClass == null) { - throw new SKException("recordClass is required"); - } - if (recordDefinition == null) { - throw new SKException("recordDefinition is required"); - } - - return new RedisJsonVectorStoreRecordMapper<>(record -> { - try { - String keyFieldName = recordDefinition.getKeyField().getEffectiveStorageName(); - ObjectNode jsonNode = objectMapper.valueToTree(record); - String key = jsonNode.get(keyFieldName).asText(); - jsonNode.remove(keyFieldName); - - return new AbstractMap.SimpleEntry<>(key, jsonNode); - } catch (Exception e) { - throw new SKException( - "Failure to serialize object, by default the Redis connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }, (storageModel, options) -> { - try { - String keyFieldName = recordDefinition.getKeyField().getEffectiveStorageName(); - ObjectNode jsonNode = objectMapper.valueToTree(storageModel.getValue()); - // Add the key back to the record - jsonNode.put(keyFieldName, storageModel.getKey()); - // Make sure to exclude the vectors if needed - if (options == null || !options.isIncludeVectors()) { - for (VectorStoreRecordVectorField vectorField : recordDefinition - .getVectorFields()) { - if (jsonNode.has(vectorField.getEffectiveStorageName())) { - jsonNode.remove(vectorField.getEffectiveStorageName()); - } - } - } - return objectMapper.convertValue(jsonNode, recordClass); - } catch (Exception e) { - throw new SKException( - "Failure to deserialize object, by default the Redis connector uses Jackson, ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisStorageType.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisStorageType.java deleted file mode 100644 index 066e65249..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisStorageType.java +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -/** - * The storage type for the Redis vector store. - */ -public enum RedisStorageType { - /** - * Redis storage with JSON module. - */ - JSON, - /** - * Redis storage with hash set. - */ - HASH_SET -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStore.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStore.java deleted file mode 100644 index 6a0f1cee8..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStore.java +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorstorage.VectorStore; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; -import redis.clients.jedis.JedisPooled; - -/** - * Represents a Redis vector store. - */ -public class RedisVectorStore implements VectorStore { - - private final JedisPooled client; - private final RedisVectorStoreOptions options; - - /** - * Creates a new instance of the Redis vector store. - * - * @param client The Redis client. - * @param options The options for the vector store. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public RedisVectorStore(@Nonnull JedisPooled client, - @Nonnull RedisVectorStoreOptions options) { - this.client = client; - this.options = options; - } - - /** - * Gets a collection from the vector store. - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - * @param The type of key in the collection. - * @param The type of record in the collection. - * @return The collection. - */ - public VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull VectorStoreRecordCollectionOptions options) { - if (!options.getKeyClass().equals(String.class)) { - throw new SKException("Redis only supports string keys"); - } - if (options.getRecordClass() == null) { - throw new SKException("Record class is required"); - } - - if (this.options.getVectorStoreRecordCollectionFactory() != null) { - return (VectorStoreRecordCollection) this.options - .getVectorStoreRecordCollectionFactory() - .createVectorStoreRecordCollection( - client, - collectionName, - options.getRecordClass(), - options.getRecordDefinition()); - } - - if (this.options.getStorageType() == RedisStorageType.JSON) { - return (VectorStoreRecordCollection) new RedisJsonVectorStoreRecordCollection<>( - client, - collectionName, - (RedisJsonVectorStoreRecordCollectionOptions) options); - } else { - return (VectorStoreRecordCollection) new RedisHashSetVectorStoreRecordCollection<>( - client, - collectionName, - (RedisHashSetVectorStoreRecordCollectionOptions) options); - } - } - - /** - * Gets the names of all collections in the vector store. - * - * @return A list of collection names. - */ - @Override - public Mono> getCollectionNamesAsync() { - return Mono.fromCallable(() -> new ArrayList<>(client.ftList())); - } - - /** - * Create a builder for the Redis vector store. - * @return A new builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder for the Redis vector store. - */ - public static class Builder implements SemanticKernelBuilder { - - @Nullable - private JedisPooled client; - @Nullable - private RedisVectorStoreOptions options; - - /** - * Sets the Redis client. - * - * @param client the Redis client - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withClient(JedisPooled client) { - this.client = client; - return this; - } - - /** - * Sets the options for the vector store. - * - * @param options the options for the vector store - * @return the builder - */ - public Builder withOptions(RedisVectorStoreOptions options) { - this.options = options; - return this; - } - - @Override - public RedisVectorStore build() { - if (client == null) { - throw new SKException("client is required"); - } - - if (options == null) { - throw new SKException("options is required"); - } - - return new RedisVectorStore(client, options); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionCreateMapping.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionCreateMapping.java deleted file mode 100644 index 05222e258..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionCreateMapping.java +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordKeyField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import com.microsoft.semantickernel.exceptions.SKException; -import redis.clients.jedis.search.Schema; - -/** - * Maps a vector store record collection to a Redis schema. - */ -public class RedisVectorStoreCollectionCreateMapping { - private static final HashSet> supportedFilterableNumericTypes = new HashSet<>( - Arrays.asList( - Integer.class, - int.class, - Double.class, - double.class, - Long.class, - long.class, - Float.class, - float.class, - Short.class, - short.class, - Byte.class, - byte.class)); - - private static String getAlgorithmMetric( - VectorStoreRecordVectorField vectorField) { - if (vectorField.getDistanceFunction() == DistanceFunction.UNDEFINED) { - return RedisVectorDistanceMetric.COSINE; - } - - switch (vectorField.getDistanceFunction()) { - case COSINE_DISTANCE: - return RedisVectorDistanceMetric.COSINE; - case DOT_PRODUCT: - return RedisVectorDistanceMetric.DOT_PRODUCT; - case EUCLIDEAN_DISTANCE: - return RedisVectorDistanceMetric.EUCLIDEAN; - default: - throw new SKException( - "Unsupported distance function: " + vectorField.getDistanceFunction()); - } - } - - private static Schema.VectorField.VectorAlgo getAlgorithmConfig( - VectorStoreRecordVectorField vectorField) { - if (vectorField.getIndexKind() == IndexKind.UNDEFINED) { - return Schema.VectorField.VectorAlgo.HNSW; - } - - switch (vectorField.getIndexKind()) { - case HNSW: - return Schema.VectorField.VectorAlgo.HNSW; - case FLAT: - return Schema.VectorField.VectorAlgo.FLAT; - default: - throw new SKException( - "Unsupported index kind: " + vectorField.getIndexKind()); - } - } - - private static String getRedisPath(String name, boolean withRedisJsonRoot) { - return withRedisJsonRoot ? "$." + name : name; - } - - /** - * Maps a vector store record collection to a Redis schema. - * - * @param fields the fields - * @param storageType the Redis storage type - * @return the schema - */ - public static Schema mapToSchema(List fields, - RedisStorageType storageType) { - Schema schema = new Schema(); - boolean withRedisJsonRoot = storageType == RedisStorageType.JSON; - - for (VectorStoreRecordField field : fields) { - if (field instanceof VectorStoreRecordKeyField) { - continue; - } - - if (field instanceof VectorStoreRecordDataField - && ((VectorStoreRecordDataField) field).isFilterable()) { - VectorStoreRecordDataField dataField = (VectorStoreRecordDataField) field; - - if (dataField.getFieldType() == null) { - throw new SKException( - "Field type is required for filterable fields: " - + dataField.getEffectiveStorageName()); - } - - if (dataField.getFieldType().equals(String.class)) { - schema.addTextField( - getRedisPath(dataField.getEffectiveStorageName(), withRedisJsonRoot), 1.0) - .as(dataField.getEffectiveStorageName()); - } else if (supportedFilterableNumericTypes.contains(dataField.getFieldType())) { - schema - .addNumericField( - getRedisPath(dataField.getEffectiveStorageName(), withRedisJsonRoot)) - .as(dataField.getEffectiveStorageName()); - } else { - throw new SKException( - "Unsupported field type for numeric filterable fields: " - + dataField.getEffectiveStorageName()); - } - - } - - if (field instanceof VectorStoreRecordVectorField) { - VectorStoreRecordVectorField vectorField = (VectorStoreRecordVectorField) field; - - if (vectorField.getDimensions() < 1) { - throw new SKException( - "Dimensions must be greater than 0 for vector fields: " - + vectorField.getEffectiveStorageName()); - } - - Schema.VectorField.VectorAlgo algorithm = getAlgorithmConfig(vectorField); - String metric = getAlgorithmMetric(vectorField); - - Map attributes = new HashMap<>(); - attributes.put(RedisIndexSchemaParams.TYPE, "FLOAT32"); - attributes.put(RedisIndexSchemaParams.DIMENSIONS, vectorField.getDimensions()); - attributes.put(RedisIndexSchemaParams.DISTANCE_METRIC, metric); - - schema.addVectorField( - getRedisPath(vectorField.getEffectiveStorageName(), withRedisJsonRoot), - algorithm, attributes).as(vectorField.getEffectiveStorageName()); - } - } - - return schema; - } - - static class RedisIndexSchemaParams { - public static final String TYPE = "TYPE"; - public static final String DIMENSIONS = "DIM"; - public static final String DISTANCE_METRIC = "DISTANCE_METRIC"; - } - - static class RedisVectorDistanceMetric { - public static final String EUCLIDEAN = "L2"; - public static final String DOT_PRODUCT = "IP"; - public static final String COSINE = "COSINE"; // Cosine distance - } - -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java deleted file mode 100644 index f029f6787..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.filter.FilterMapping; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; -import redis.clients.jedis.args.SortingOrder; -import redis.clients.jedis.search.FTSearchParams; - -/** - * A mapping for searching a collection of vector records in Redis. - */ -public class RedisVectorStoreCollectionSearchMapping implements FilterMapping { - - static final String VECTOR_SCORE_FIELD = "vector_score"; - - private RedisVectorStoreCollectionSearchMapping() { - } - - static class RedisVectorStoreCollectionSearchMappingHolder { - static final RedisVectorStoreCollectionSearchMapping INSTANCE = new RedisVectorStoreCollectionSearchMapping(); - } - - static RedisVectorStoreCollectionSearchMapping getInstance() { - return RedisVectorStoreCollectionSearchMappingHolder.INSTANCE; - } - - /** - * Builds a query for searching a collection of vector records in Redis. - * @param vector the vector to search for - * @param options the search options - * @param recordDefinition the record definition - * @param storageType the storage type - * @return the query and search parameters - */ - public Pair buildQuery(List vector, - VectorSearchOptions options, - VectorStoreRecordDefinition recordDefinition, - RedisStorageType storageType) { - VectorStoreRecordVectorField firstVectorField = recordDefinition.getVectorFields().get(0); - if (options == null) { - options = VectorSearchOptions.createDefault(firstVectorField.getName()); - } - - VectorStoreRecordVectorField vectorField = options.getVectorFieldName() == null - ? firstVectorField - : (VectorStoreRecordVectorField) recordDefinition - .getField(options.getVectorFieldName()); - - String filter = getFilter(options.getVectorSearchFilter(), recordDefinition); - - String knn = String.format("%s=>[KNN $K @%s $BLOB AS %s]", filter, - vectorField.getEffectiveStorageName(), VECTOR_SCORE_FIELD); - - FTSearchParams searchParams = new FTSearchParams() - .addParam("K", options.getTop() + options.getSkip()) - .addParam("BLOB", convertListToByteArray(vector)) - .limit(options.getSkip(), options.getTop()) - .sortBy(VECTOR_SCORE_FIELD, SortingOrder.ASC) - .dialect(2); - - // For hash set storage is possible to select what fields to return without them being filterable - if (storageType == RedisStorageType.HASH_SET) { - // We also need to tell Redis to return the fields without decoding them - // Vector fields specially need to be returned as raw bytes - for (VectorStoreRecordDataField dataField : recordDefinition.getDataFields()) { - searchParams.returnField(dataField.getEffectiveStorageName(), false); - } - if (options.isIncludeVectors()) { - for (VectorStoreRecordVectorField v : recordDefinition.getVectorFields()) { - searchParams.returnField(v.getEffectiveStorageName(), false); - } - } - - // Also, return the score field, this can be decoded. - searchParams.returnField(VECTOR_SCORE_FIELD, true); - } - - return Pair.of(knn, searchParams); - } - - /** - * Converts a list of floats to a byte array. - * @param embeddings the embeddings - * @return the byte array - */ - public static byte[] convertListToByteArray(List embeddings) { - ByteBuffer bytes = ByteBuffer.allocate(Float.BYTES * embeddings.size()); - bytes.order(ByteOrder.LITTLE_ENDIAN); - embeddings.iterator().forEachRemaining(bytes::putFloat); - return bytes.array(); - } - - /** - * Converts a byte array to a list of floats. - * @param bytes the byte array - * @return the list of floats - */ - public static List convertByteArrayToList(byte[] bytes) { - ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); - List embeddings = new java.util.ArrayList<>(); - while (buffer.hasRemaining()) { - embeddings.add(buffer.getFloat()); - } - return embeddings; - } - - /** - * Gets the filter string for the given vector search filter and record definition. - * - * @param filter The filter to get the filter string for. - * @param recordDefinition The record definition to get the filter string for. - * @return The filter string. - */ - @Override - public String getFilter(VectorSearchFilter filter, - VectorStoreRecordDefinition recordDefinition) { - if (filter == null - || filter.getFilterClauses().isEmpty()) { - return "*"; - } - - return String.format("(%s)", - filter.getFilterClauses().stream().map(filterClause -> { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - return getEqualToFilter(new EqualToFilterClause( - recordDefinition.getField(equalToFilterClause.getFieldName()) - .getEffectiveStorageName(), - equalToFilterClause.getValue())); - } else { - throw new SKException("Unsupported filter clause type '" - + filterClause.getClass().getSimpleName() + "'."); - } - }).collect(Collectors.joining(" "))); - } - - /** - * Gets the filter string for the given equal to filter clause. - * - * @param filterClause The equal to filter clause to get the filter string for. - * @return The filter string. - */ - @Override - public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = filterClause.getFieldName(); - Object value = filterClause.getValue(); - String formattedValue; - - if (value instanceof String) { - formattedValue = String.format("\"%s\"", value); - } else if (value instanceof Number) { - formattedValue = String.format("[%s %s]", value, value); - } else { - throw new SKException("Unsupported filter value type '" - + value.getClass().getSimpleName() + "'."); - } - - return String.format("@%s:%s", fieldName, formattedValue); - } - - /** - * Gets the filter string for the given any tag equal to filter clause. - * - * @param filterClause The any tag equal to filter clause to get the filter string for. - * @return The filter string. - */ - @Override - public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - return String.format("@%s:\"%s\"", filterClause.getFieldName(), filterClause.getValue()); - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreOptions.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreOptions.java deleted file mode 100644 index 730930278..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreOptions.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.microsoft.semantickernel.exceptions.SKException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Options for the Redis vector store. - */ -public class RedisVectorStoreOptions { - @Nullable - private final RedisVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - - @Nonnull - private final RedisStorageType storageType; - - /** - * Creates a new instance of the Redis vector store options. - * @param storageType The storage type. - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - */ - public RedisVectorStoreOptions( - @Nonnull RedisStorageType storageType, - @Nullable RedisVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.storageType = storageType; - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - } - - /** - * Creates a new instance of the Redis vector store options. - */ - public RedisVectorStoreOptions() { - this(RedisStorageType.JSON, null); - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Gets the vector store record collection factory. - * - * @return the vector store record collection factory - */ - @Nullable - public RedisVectorStoreRecordCollectionFactory getVectorStoreRecordCollectionFactory() { - return vectorStoreRecordCollectionFactory; - } - - /** - * Gets the storage type. - * - * @return the storage type - */ - @Nonnull - public RedisStorageType getStorageType() { - return storageType; - } - - /** - * Builder for Redis vector store options. - */ - public static class Builder { - @Nullable - private RedisVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory; - @Nullable - private RedisStorageType storageType; - - /** - * Sets the vector store record collection factory. - * - * @param vectorStoreRecordCollectionFactory The vector store record collection factory. - * @return The updated builder instance. - */ - public Builder withVectorStoreRecordCollectionFactory( - RedisVectorStoreRecordCollectionFactory vectorStoreRecordCollectionFactory) { - this.vectorStoreRecordCollectionFactory = vectorStoreRecordCollectionFactory; - return this; - } - - /** - * Sets the storage type. - * - * @param storageType The storage type. - * @return The updated builder instance. - */ - public Builder withStorageType(RedisStorageType storageType) { - this.storageType = storageType; - return this; - } - - /** - * Builds the options. - * - * @return The options. - */ - public RedisVectorStoreOptions build() { - if (storageType == null) { - throw new SKException("storageType is required"); - } - - return new RedisVectorStoreOptions(storageType, vectorStoreRecordCollectionFactory); - } - } -} diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreRecordCollectionFactory.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreRecordCollectionFactory.java deleted file mode 100644 index bb1ab9a4b..000000000 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreRecordCollectionFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.redis; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import redis.clients.jedis.JedisPooled; - -/** - * Factory for creating Redis vector store record collections. - */ -public interface RedisVectorStoreRecordCollectionFactory { - - /** - * Creates a new vector store record collection. - * - * @param client The Redis client. - * @param collectionName The name of the collection. - * @param recordClass The class type of the record. - * @param recordDefinition The record definition. - * @param The type of the records in the collection. - * @return The collection. - */ - VectorStoreRecordCollection createVectorStoreRecordCollection( - JedisPooled client, - String collectionName, - Class recordClass, - VectorStoreRecordDefinition recordDefinition); -} diff --git a/data/semantickernel-data-sqlite/pom.xml b/data/semantickernel-data-sqlite/pom.xml deleted file mode 100644 index fc4d80186..000000000 --- a/data/semantickernel-data-sqlite/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-data-sqlite - Semantic Kernel SQLite JDBC driver connector - Provides a SQLite connector for the Semantic Kernel - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.xerial - sqlite-jdbc - 3.47.0.0 - - - \ No newline at end of file diff --git a/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java b/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java deleted file mode 100644 index 57de12257..000000000 --- a/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.jdbc.sqlite; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDataField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; - -/** - * A query provider for a vector store in SQLite. - */ -public class SQLiteVectorStoreQueryProvider extends - JDBCVectorStoreQueryProvider implements SQLVectorStoreQueryProvider { - - private final DataSource dataSource; - private final ObjectMapper objectMapper; - - @SuppressFBWarnings("EI_EXPOSE_REP2") - private SQLiteVectorStoreQueryProvider( - @Nonnull DataSource dataSource, - @Nonnull String collectionsTable, - @Nonnull String prefixForCollectionTables, - @Nonnull ObjectMapper objectMapper) { - super(dataSource, collectionsTable, prefixForCollectionTables); - this.dataSource = dataSource; - this.objectMapper = objectMapper; - } - - /** - * Creates a new builder. - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - private void setUpsertStatementValues(PreparedStatement statement, Object record, - List fields) { - JsonNode jsonNode = objectMapper.valueToTree(record); - - for (int i = 0; i < fields.size(); ++i) { - VectorStoreRecordField field = fields.get(i); - try { - JsonNode valueNode = jsonNode.get(field.getEffectiveStorageName()); - - if (field instanceof VectorStoreRecordVectorField) { - // Convert the vector field to a string - if (!field.getFieldType().equals(String.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } else if (field instanceof VectorStoreRecordDataField) { - // Convert List field to a string - if (field.getFieldType().equals(List.class)) { - statement.setObject(i + 1, objectMapper.writeValueAsString(valueNode)); - continue; - } - } - - statement.setObject(i + 1, - objectMapper.convertValue(valueNode, field.getFieldType())); - } catch (SQLException | JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - /** - * Upserts records into the collection. - * @param collectionName the collection name - * @param records the records to upsert - * @param recordDefinition the record definition - * @param options the upsert options - * @throws SKException if the upsert fails - */ - @Override - @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") // SQL query is generated dynamically with valid identifiers - public void upsertRecords(String collectionName, List records, - VectorStoreRecordDefinition recordDefinition, UpsertRecordOptions options) { - List fields = recordDefinition.getAllFields(); - - String query = formatQuery("INSERT OR REPLACE INTO %s (%s) VALUES (%s)", - getCollectionTableName(collectionName), - getQueryColumnsFromFields(fields), - getWildcardString(fields.size())); - - try (Connection connection = dataSource.getConnection(); - PreparedStatement statement = connection.prepareStatement(query)) { - for (Object record : records) { - setUpsertStatementValues(statement, record, recordDefinition.getAllFields()); - statement.addBatch(); - } - - statement.executeBatch(); - } catch (SQLException e) { - throw new SKException("Failed to upsert records", e); - } - } - - @Override - protected String getInsertCollectionQuery(String collectionsTable) { - return formatQuery( - "INSERT OR IGNORE INTO %s (collectionId) VALUES (?)", - validateSQLidentifier(collectionsTable)); - } - - /** - * A builder for {@code SQLiteVectorStoreQueryProvider}. - */ - public static class Builder - extends JDBCVectorStoreQueryProvider.Builder { - private DataSource dataSource; - private String collectionsTable = DEFAULT_COLLECTIONS_TABLE; - private String prefixForCollectionTables = DEFAULT_PREFIX_FOR_COLLECTION_TABLES; - private ObjectMapper objectMapper = new ObjectMapper(); - - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withDataSource(DataSource dataSource) { - this.dataSource = dataSource; - return this; - } - - /** - * Sets the collections table name. - * @param collectionsTable the collections table name - * @return the builder - */ - public Builder withCollectionsTable(String collectionsTable) { - this.collectionsTable = validateSQLidentifier(collectionsTable); - return this; - } - - /** - * Sets the prefix for collection tables. - * @param prefixForCollectionTables the prefix for collection tables - * @return the builder - */ - public Builder withPrefixForCollectionTables(String prefixForCollectionTables) { - this.prefixForCollectionTables = validateSQLidentifier(prefixForCollectionTables); - return this; - } - - /** - * Sets the object mapper. - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - public SQLiteVectorStoreQueryProvider build() { - if (dataSource == null) { - throw new SKException("DataSource is required"); - } - - return new SQLiteVectorStoreQueryProvider(dataSource, collectionsTable, - prefixForCollectionTables, objectMapper); - } - } -} diff --git a/eclipse-formatter.xml b/eclipse-formatter.xml deleted file mode 100644 index 576a3375a..000000000 --- a/eclipse-formatter.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml b/learnDocs/LightsApp/pom.xml similarity index 69% rename from samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml rename to learnDocs/LightsApp/pom.xml index 1bf80430f..84b9fd499 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml +++ b/learnDocs/LightsApp/pom.xml @@ -1,15 +1,12 @@ - - + + + 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - semantickernel-text-splitter-plugin - semantickernel-text-splitter-plugin + com.microsoft.semantic-kernel + LightsApp + 1.2.0-SNAPSHOT jar @@ -17,7 +14,7 @@ com.microsoft.semantic-kernel semantickernel-bom - ${project.version} + 1.2.0 pom import @@ -29,25 +26,23 @@ com.microsoft.semantic-kernel semantickernel-api - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - org.apache.logging.log4j log4j-api runtime + 2.22.1 org.apache.logging.log4j log4j-core runtime + 2.22.1 org.apache.logging.log4j log4j-slf4j2-impl runtime + 2.22.1 com.fasterxml.jackson.core @@ -60,22 +55,29 @@ compile - org.junit.jupiter - junit-jupiter-api - test + com.azure + azure-identity + + + com.microsoft.semantic-kernel + semantickernel-aiservices-openai + + + com.google.code.gson + gson + 2.10.1 - org.apache.maven.plugins maven-compiler-plugin - 17 - 17 + 15 + 15 - + \ No newline at end of file diff --git a/learnDocs/LightsApp/src/main/java/LightModel.java b/learnDocs/LightsApp/src/main/java/LightModel.java new file mode 100644 index 000000000..1ec7f60af --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/LightModel.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. + +// +public class LightModel { + + private int id; + private String name; + private Boolean isOn; + + public LightModel(int id, String name, Boolean isOn) { + this.id = id; + this.name = name; + this.isOn = isOn; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getIsOn() { + return isOn; + } + + public void setIsOn(Boolean isOn) { + this.isOn = isOn; + } +} +// \ No newline at end of file diff --git a/learnDocs/LightsApp/src/main/java/LightsApp.java b/learnDocs/LightsApp/src/main/java/LightsApp.java new file mode 100644 index 000000000..df4f3ffa4 --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/LightsApp.java @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft. All rights reserved. + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.google.gson.Gson; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; +import com.microsoft.semantickernel.orchestration.InvocationContext; +import com.microsoft.semantickernel.orchestration.InvocationReturnMode; +import com.microsoft.semantickernel.orchestration.ToolCallBehavior; +import com.microsoft.semantickernel.plugin.KernelPlugin; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; +import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; +import java.util.List; +import java.util.Scanner; + +public class LightsApp { + + private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); + private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); + private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-4o"); + + public static void main(String[] args) throws Exception { + + // + OpenAIAsyncClient client = new OpenAIClientBuilder() + .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) + .endpoint(CLIENT_ENDPOINT) + .buildAsyncClient(); + + // + // Import the LightsPlugin + KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(), + "LightsPlugin"); + // + + // + // Create your AI service client + ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() + .withModelId(MODEL_ID) + .withOpenAIAsyncClient(client) + .build(); + + // + // Create a kernel with Azure OpenAI chat completion and plugin + Kernel kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chatCompletionService) + .withPlugin(lightPlugin) + .build(); + // + // + + // Add a converter to the kernel to show it how to serialise LightModel objects into a prompt + ContextVariableTypes + .addGlobalConverter( + ContextVariableTypeConverter.builder(LightModel.class) + .toPromptString(new Gson()::toJson) + .build()); + + // + // Enable planning + InvocationContext invocationContext = new InvocationContext.Builder() + .withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY) + .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) + .build(); + // + + // Create a history to store the conversation + ChatHistory history = new ChatHistory(); + + // Initiate a back-and-forth chat + Scanner scanner = new Scanner(System.in); + String userInput; + do { + // Collect user input + System.out.print("User > "); + + // + userInput = scanner.nextLine(); + // Add user input + history.addUserMessage(userInput); + + // Prompt AI for response to users input + List> results = chatCompletionService + .getChatMessageContentsAsync(history, kernel, invocationContext) + .block(); + // + + for (ChatMessageContent result : results) { + // Print the results + if (result.getAuthorRole() == AuthorRole.ASSISTANT && result.getContent() != null) { + System.out.println("Assistant > " + result); + } + // Add the message from the agent to the chat history + history.addMessage(result); + } + } while (userInput != null && !userInput.isEmpty()); + + // + } +} diff --git a/learnDocs/LightsApp/src/main/java/LightsAppNonInteractive.java b/learnDocs/LightsApp/src/main/java/LightsAppNonInteractive.java new file mode 100644 index 000000000..c5b6753fe --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/LightsAppNonInteractive.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft. All rights reserved. + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.google.gson.Gson; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; +import com.microsoft.semantickernel.orchestration.InvocationContext; +import com.microsoft.semantickernel.orchestration.InvocationReturnMode; +import com.microsoft.semantickernel.orchestration.ToolCallBehavior; +import com.microsoft.semantickernel.plugin.KernelPlugin; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; +import java.util.List; + +public class LightsAppNonInteractive { + + private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); + private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); + private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-4o"); + + public static void main(String[] args) { + + // + OpenAIAsyncClient client = new OpenAIClientBuilder() + .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) + .endpoint(CLIENT_ENDPOINT) + .buildAsyncClient(); + + // + // Import the LightsPlugin + KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(), + "LightsPlugin"); + // + + // + // Create your AI service client + ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() + .withModelId(MODEL_ID) + .withOpenAIAsyncClient(client) + .build(); + + // + // Create a kernel with Azure OpenAI chat completion and plugin + Kernel kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chatCompletionService) + .withPlugin(lightPlugin) + .build(); + // + // + + // Add a converter to the kernel to show it how to serialise LightModel objects into a prompt + ContextVariableTypes + .addGlobalConverter( + ContextVariableTypeConverter.builder(LightModel.class) + .toPromptString(new Gson()::toJson) + .build()); + + // + // + // Enable planning + InvocationContext invocationContext = new InvocationContext.Builder() + .withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY) + .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) + .build(); + // + + // Create a history to store the conversation + ChatHistory history = new ChatHistory(); + history.addUserMessage("Turn on light 2"); + + List> results = chatCompletionService + .getChatMessageContentsAsync(history, kernel, invocationContext) + .block(); + + System.out.println("Assistant > " + results.get(0)); + // + } +} diff --git a/learnDocs/LightsApp/src/main/java/LightsPlugin.java b/learnDocs/LightsApp/src/main/java/LightsPlugin.java new file mode 100644 index 000000000..15eedf721 --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/LightsPlugin.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. + +import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; +import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +// +public class LightsPlugin { + + // Mock data for the lights + private final Map lights = new HashMap<>(); + + public LightsPlugin() { + lights.put(1, new LightModel(1, "Table Lamp", false)); + lights.put(2, new LightModel(2, "Porch light", false)); + lights.put(3, new LightModel(3, "Chandelier", true)); + } + + @DefineKernelFunction(name = "get_lights", description = "Gets a list of lights and their current state") + public List getLights() { + System.out.println("Getting lights"); + return new ArrayList<>(lights.values()); + } + + @DefineKernelFunction(name = "change_state", description = "Changes the state of the light") + public LightModel changeState( + @KernelFunctionParameter(name = "id", description = "The ID of the light to change") int id, + @KernelFunctionParameter(name = "isOn", description = "The new state of the light") boolean isOn) { + System.out.println("Changing light " + id + " " + isOn); + if (!lights.containsKey(id)) { + throw new IllegalArgumentException("Light not found"); + } + + lights.get(id).setIsOn(isOn); + + return lights.get(id); + } +} +// \ No newline at end of file diff --git a/learnDocs/LightsApp/src/main/java/withbrightness/LightModel.java b/learnDocs/LightsApp/src/main/java/withbrightness/LightModel.java new file mode 100644 index 000000000..174de9919 --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/withbrightness/LightModel.java @@ -0,0 +1,68 @@ +package withbrightness; +// Copyright (c) Microsoft. All rights reserved. + +// +public class LightModel { + + private int id; + private String name; + private Boolean isOn; + private Brightness brightness; + private String color; + + + public enum Brightness { + LOW, + MEDIUM, + HIGH + } + + public LightModel(int id, String name, Boolean isOn, Brightness brightness, String color) { + this.id = id; + this.name = name; + this.isOn = isOn; + this.brightness = brightness; + this.color = color; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getIsOn() { + return isOn; + } + + public void setIsOn(Boolean isOn) { + this.isOn = isOn; + } + + public Brightness getBrightness() { + return brightness; + } + + public void setBrightness(Brightness brightness) { + this.brightness = brightness; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} +// \ No newline at end of file diff --git a/learnDocs/LightsApp/src/main/java/withbrightness/LightsAppNonInteractive.java b/learnDocs/LightsApp/src/main/java/withbrightness/LightsAppNonInteractive.java new file mode 100644 index 000000000..c5b387f1a --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/withbrightness/LightsAppNonInteractive.java @@ -0,0 +1,116 @@ +package withbrightness;// Copyright (c) Microsoft. All rights reserved. + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.google.gson.Gson; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; +import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; +import com.microsoft.semantickernel.orchestration.InvocationContext; +import com.microsoft.semantickernel.orchestration.InvocationReturnMode; +import com.microsoft.semantickernel.orchestration.ToolCallBehavior; +import com.microsoft.semantickernel.plugin.KernelPlugin; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; + +import java.util.List; + +public class LightsAppNonInteractive { + + private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); + private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); + private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-4o"); + + public static void main(String[] args) { + + // + OpenAIAsyncClient client = new OpenAIClientBuilder() + .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) + .endpoint(CLIENT_ENDPOINT) + .buildAsyncClient(); + + // + // Import the LightsPlugin + KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(), + "LightsPlugin"); + // + + // + // Create your AI service client + ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() + .withModelId(MODEL_ID) + .withOpenAIAsyncClient(client) + .build(); + + // + // Create a kernel with Azure OpenAI chat completion and plugin + Kernel kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chatCompletionService) + .withPlugin(lightPlugin) + .build(); + // + // + + + // Add a converter to the kernel to show it how to serialise LightModel objects into a prompt + ContextVariableTypes + .addGlobalConverter( + ContextVariableTypeConverter.builder(LightModel.class) + .toPromptString(new Gson()::toJson) + .fromObject(it -> { + if (it instanceof String) { + try { + return new Gson().fromJson((String) it, LightModel.class); + } catch (Exception e) { + throw new RuntimeException("Cannot convert to LightModel"); + } + } + return null; + }) + .fromPromptString(string -> { + return new Gson().fromJson(string, LightModel.class); + }) + .build()); + + // + // + // Enable planning + InvocationContext invocationContext = new InvocationContext.Builder() + .withReturnMode(InvocationReturnMode.FULL_HISTORY) + .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) + .build(); + // + + // Create a history to store the conversation + ChatHistory history = new ChatHistory(); + history.addUserMessage("Turn on light 2"); + + List> results = chatCompletionService + .getChatMessageContentsAsync(history, kernel, invocationContext) + .block(); + + System.out.println("Assistant > " + results.get(results.size() - 1)); + + history.addUserMessage("Decrease brightness of light 1"); + + results = chatCompletionService + .getChatMessageContentsAsync(history, kernel, invocationContext) + .block(); + + System.out.println("Assistant > " + results.get(results.size() - 1)); + + + history.addUserMessage("What is the state of all the lights?"); + + results = chatCompletionService + .getChatMessageContentsAsync(history, kernel, invocationContext) + .block(); + + System.out.println("Assistant > " + results.get(results.size() - 1)); + // + } +} diff --git a/learnDocs/LightsApp/src/main/java/withbrightness/LightsPlugin.java b/learnDocs/LightsApp/src/main/java/withbrightness/LightsPlugin.java new file mode 100644 index 000000000..d02b40e54 --- /dev/null +++ b/learnDocs/LightsApp/src/main/java/withbrightness/LightsPlugin.java @@ -0,0 +1,47 @@ +package withbrightness;// Copyright (c) Microsoft. All rights reserved. + +import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; +import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +// +public class LightsPlugin { + + // Mock data for the lights + private final Map lights = new HashMap<>(); + + public LightsPlugin() { + lights.put(1, new LightModel(1, "Table Lamp", false, LightModel.Brightness.MEDIUM, "#FFFFFF")); + lights.put(2, new LightModel(2, "Porch light", false, LightModel.Brightness.HIGH, "#FF0000")); + lights.put(3, new LightModel(3, "Chandelier", true, LightModel.Brightness.LOW, "#FFFF00")); + } + + @DefineKernelFunction(name = "get_lights", description = "Gets a list of lights and their current state") + public List getLights() { + System.out.println("Getting lights"); + return new ArrayList<>(lights.values()); + } + + @DefineKernelFunction(name = "change_state", description = "Changes the state of the light") + public LightModel changeState( + @KernelFunctionParameter( + name = "model", + description = "The new state of the model to set. Example model: " + + "{\"id\":99,\"name\":\"Head Lamp\",\"isOn\":false,\"brightness\":\"MEDIUM\",\"color\":\"#FFFFFF\"}", + type = LightModel.class) LightModel model + ) { + System.out.println("Changing light " + model.getId() + " " + model.getIsOn()); + if (!lights.containsKey(model.getId())) { + throw new IllegalArgumentException("Light not found"); + } + + lights.put(model.getId(), model); + + return lights.get(model.getId()); + } +} +// \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/resources/log4j2.xml b/learnDocs/LightsApp/src/main/resources/log4j2.xml similarity index 100% rename from samples/semantickernel-learn-resources/src/main/resources/log4j2.xml rename to learnDocs/LightsApp/src/main/resources/log4j2.xml diff --git a/mvnw b/mvnw deleted file mode 100755 index 19529ddf8..000000000 --- a/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd deleted file mode 100644 index 249bdf382..000000000 --- a/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml deleted file mode 100644 index b096c4a4b..000000000 --- a/pom.xml +++ /dev/null @@ -1,935 +0,0 @@ - - - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - pom - - https://www.github.com/microsoft/semantic-kernel - Semantic Kernel Parent - Parent pom for the Semantic Kernel Project - - - 1.0.0-beta.16 - 10.18.2 - 0.10.21 - false - 2.19.1 - 1.17.0 - 1.6.0 - 5.11.3 - 2.25.3 - 3.1.0 - 2.12.1 - 3.5.0 - 3.4.0 - 3.13.0 - 8 - 8 - 8 - 3.8.0 - 3.1.3 - 1.0 - 3.5.0 - 3.5.0 - 3.1.3 - 0.8.12 - 3.4.2 - 3.10.1 - 3.5.0 - 2.4.0 - - 3.27.0 - 3.8.0 - 0.16.1 - 3.1.1 - 3.3.1 - 4.0.0-M16 - 3.6.0 - 3.3.1 - 4.8.6.5 - - 2.38.0 - 3.5.1 - 3.9.9 - 2.17.1 - 5.14.2 - 0.9.1 - - 7.10.0 - UTF-8 - microsoft/semantic-kernel - git@github.com:${project.github.repository}.git - 4.8.6 - - - - semantickernel-bom - semantickernel-api - semantickernel-experimental - aiservices/openai - aiservices/google - aiservices/huggingface - data/semantickernel-data-azureaisearch - data/semantickernel-data-jdbc - data/semantickernel-data-redis - data/semantickernel-data-mysql - data/semantickernel-data-hsqldb - data/semantickernel-data-postgres - data/semantickernel-data-sqlite - data/semantickernel-data-oracle - agents/semantickernel-agents-core - semantickernel-api-data - semantickernel-api-exceptions - semantickernel-api-builders - semantickernel-api-textembedding-services - semantickernel-api-localization - semantickernel-api-ai-services - - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - org.junit.jupiter - junit-jupiter - ${junit5.version} - test - - - org.junit.jupiter - junit-jupiter-api - ${junit5.version} - test - - - org.apache.logging.log4j - log4j-api - ${log4j2.version} - test - - - org.apache.logging.log4j - log4j-core - ${log4j2.version} - test - - - org.apache.logging.log4j - log4j-slf4j2-impl - ${log4j2.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - com.azure - azure-ai-openai - ${azure-ai-openai.version} - - - com.microsoft.semantic-kernel - semantickernel-connectors-ai-openai - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-builders - ${project.version} - provided - - - com.microsoft.semantic-kernel - semantickernel-api-data - ${project.version} - provided - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - ${project.version} - provided - - - com.microsoft.semantic-kernel - semantickernel-api-localization - ${project.version} - provided - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - ${project.version} - provided - - - com.microsoft.semantic-kernel.extensions - semantickernel-sequentialplanner-extension - ${project.version} - - - com.microsoft.semantic-kernel.extensions - semantickernel-actionplanner-extension - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - ${project.version} - provided - - - - - com.github.spotbugs - spotbugs-annotations - ${spotbugs.version} - - - - org.wiremock - wiremock - 3.9.2 - test - - - org.mockito - mockito-junit-jupiter - 5.14.2 - test - - - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - provided - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-localization - provided - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - provided - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - provided - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-api-data - provided - ${project.version} - - - - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - ${maven.spotbugs-plugin.version} - - - com.github.spotbugs - spotbugs - ${spotbugs.version} - - - - - org.apache.maven.plugins - maven-changes-plugin - ${maven.changes-plugin.version} - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven.checkstyle-plugin.version} - - - com.puppycrawl.tools - checkstyle - ${checkstyle.version} - - - - - org.apache.maven.plugins - maven-clean-plugin - ${maven.clean-plugin.version} - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler-plugin.version} - - ${maven.compiler.release} - ${maven.compiler.release} - 8 - -Xlint:unchecked - - - - org.apache.maven.plugins - maven-dependency-plugin - ${maven.dependency-plugin.version} - - - org.apache.maven.plugins - maven-deploy-plugin - ${maven.deploy-plugin.version} - - - org.apache.maven.plugins - maven-enforcer-plugin - ${maven.enforcer-plugin.version} - - - enforce-maven - - enforce - - - - - ${maven.version} - - - - - - - - org.apache.maven.plugins - maven-install-plugin - ${maven.install-plugin.version} - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar-plugin.version} - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven.javadoc-plugin.version} - - - false - true - public - *.implementation.*:*.implementation - - - - org.apache.maven.plugins - maven-jxr-plugin - ${maven.jxr-plugin.version} - - - org.apache.maven.plugins - maven-pmd-plugin - ${maven.pmd-plugin.version} - - - net.sourceforge.pmd - pmd-core - ${pmd.version} - - - net.sourceforge.pmd - pmd-java - ${pmd.version} - - - net.sourceforge.pmd - pmd-javascript - ${pmd.version} - - - net.sourceforge.pmd - pmd-jsp - ${pmd.version} - - - org.apache.maven.plugins - maven-pmd-plugin - ${maven.pmd-plugin.version} - - - - - org.apache.maven.plugins - maven-release-plugin - ${maven.release-plugin.version} - - - org.apache.maven.plugins - maven-shade-plugin - ${maven.shade-plugin.version} - - - org.apache.maven.plugins - maven-source-plugin - ${maven.source-plugin.version} - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven.surefire-plugin.version} - - - org.apache.maven.plugins - maven-site-plugin - ${maven.site-plugin.version} - - - org.apache.maven.plugins - maven-project-info-reports-plugin - ${maven.project-info-reports-plugin.version} - - - org.apache.maven.plugins - maven-resources-plugin - ${maven.resources-plugin.version} - - - org.apache.maven.plugins - maven-antrun-plugin - ${maven.antrun-plugin.version} - - - org.apache.rat - apache-rat-plugin - ${maven.rat-plugin.version} - - - org.codehaus.mojo - exec-maven-plugin - ${maven.exec-plugin.version} - - - org.codehaus.mojo - license-maven-plugin - ${maven.license-plugin.version} - - Microsoft - 2023 - mit - ${basedir}/target/LICENSE - - - - org.codehaus.mojo - versions-maven-plugin - ${maven.versions-plugin.version} - - - org.commonjava.maven.plugins - directory-maven-plugin - ${maven.directory-maven-plugin.version} - - - org.jacoco - jacoco-maven-plugin - ${maven.jacoco-plugin.version} - - - - prepare-agent - - - - report - prepare-package - - report - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.24 - - - android - test - - check - - - - - - - net.sf.androidscents.signature - android-api-level-26 - 8.0.0_r2 - - - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - - org.apache.maven.plugins - maven-enforcer-plugin - - - org.codehaus.mojo - license-maven-plugin - - - - update-project-license - - - - add-third-party - - add-third-party - - - compile,runtime - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.0 - - - attach-sources - verify - - jar-no-fork - - - - - - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - - - org.mutabilitydetector - MutabilityDetector4FindBugs - ${mutability.detector.version} - - - - - - org.apache.maven.plugins - maven-changes-plugin - - - - - - changes-report - - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - checkstyle - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - org.apache.maven.plugins - maven-javadoc-plugin - - - org.apache.maven.plugins - maven-jxr-plugin - - - org.apache.maven.plugins - maven-pmd-plugin - - ${maven.compiler.release} - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - - - org.apache.rat - apache-rat-plugin - - - org.codehaus.mojo - license-maven-plugin - - - org.codehaus.mojo - versions-maven-plugin - - - - dependency-updates-report - plugin-updates-report - property-updates-report - - - - - - org.jacoco - jacoco-maven-plugin - ${maven.jacoco-plugin.version} - - - - - - - central - - true - - - false - - https://repo1.maven.org/maven2/ - - - - - - compile-jdk8 - - 1.8 - 1.8 - true - - - - - compile-jdk17 - - true - - - 17 - 17 - - - - bug-check - - false - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler-plugin.version} - - ${maven.compiler.release} - ${maven.compiler.release} - - 8 - ${project.build.sourceEncoding} - true - - -XDcompilePolicy=simple - - - -Xplugin:ErrorProne - -XepOpt:NullAway:AnnotatedPackages=com.microsoft.semantickernel - -Xep:AlmostJavadoc:OFF -Xep:MissingSummary:OFF - -Xep:UnusedVariable:OFF -Xep:EmptyBlockTag:OFF - -XepExcludedPaths:.*/src/test/java/.* - - - - - com.google.errorprone - error_prone_core - ${google.errorprone.core.version} - - - com.uber.nullaway - nullaway - ${com.uber.nullaway.version} - - - - - - com.diffplug.spotless - spotless-maven-plugin - ${maven.spotless-plugin.version} - - - check - - check - - compile - - - apply - - apply - - process-sources - - - - ${compilingJdk8} - - - 4.30 - ./eclipse-formatter.xml - - - - // Copyright (c) Microsoft. All rights reserved. - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - ${maven.spotbugs-plugin.version} - - Max - - Normal - - - - - spotbugs - check - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - - - - - - - with-samples - - samples - api-test - - - - release - - 1.8 - 1.8 - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - - jar - - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - true - - - - org.apache.maven.plugins - maven-release-plugin - - java-@{project.version} - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - - - - - ${releaseRepoId} - ${releaseRepoUrl} - ${releaseRepoName} - - - - - ${releaseRepoId} - ${releaseRepoUrl} - ${releaseRepoName} - - - - - github-packages - - false - - - - github - GitHub Packages - https://maven.pkg.github.com/microsoft/semantic-kernel-java - - - - - central - https://repo1.maven.org/maven2 - - - github - GitHub Packages - https://maven.pkg.github.com/microsoft/semantic-kernel-java - - true - - - - - - - - - microsoft - Microsoft - - - - - - MIT License - https://opensource.org/licenses/MIT - repo - - - - - https://github.com/microsoft/semantic-kernel - scm:git:https://github.com/microsoft/semantic-kernel.git - scm:git:https://github.com/microsoft/semantic-kernel.git - HEAD - - diff --git a/samples/README.md b/samples/README.md deleted file mode 100644 index 660690a87..000000000 --- a/samples/README.md +++ /dev/null @@ -1,8 +0,0 @@ -## Kernel Samples - -| Type | Description | -|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| [semantickernel-demos](semantickernel-demos) | Look here to find a sample which demonstrate how to use many of Semantic Kernel features. | -| [semantickernel-learn-resources](semantickernel-learn-resources) | Code snippets that are related to online documentation sources like Microsoft Learn, DevBlogs and others | -| [semantickernel-concepts](semantickernel-concepts) | This section contains samples which illustrate how to use Semantic Kernel concepts. | -| [semantickernel-sample-plugins](semantickernel-sample-plugins) | This section contains samples which illustrate how to create Semantic Kernel plugins. | \ No newline at end of file diff --git a/samples/example.conf.properties b/samples/example.conf.properties deleted file mode 100644 index f41f25b4d..000000000 --- a/samples/example.conf.properties +++ /dev/null @@ -1,6 +0,0 @@ -client.openai.key=OPEN_AI_KEY -client.openai.organizationid=OPEN_AI_ORGANIZATION_ID - -client.azureopenai.key=AZURE_OPEN_AI_KEY -client.azureopenai.endpoint=AZURE_OPEN_AI_ENDPOINT -client.azureopenai.deploymentname=AZURE_OPEN_AI_DEPLOYMENT_NAME diff --git a/samples/pom.xml b/samples/pom.xml deleted file mode 100644 index d2bea638a..000000000 --- a/samples/pom.xml +++ /dev/null @@ -1,154 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-samples-parent - pom - Semantic Kernel Samples Parent - Parent pom for sample code for using the Semantic Kernel project - - - semantickernel-concepts - semantickernel-demos - semantickernel-learn-resources - semantickernel-sample-plugins - - - - 0.10.21 - 2.19.1 - 2.20.0 - 3.11.0 - 17 - 17 - 17 - UTF-8 - - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - import - pom - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler-plugin.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven.compiler.release} - ${maven.compiler.release} - ${maven.compiler.release} - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.3.0 - - - enforce-maven - - enforce - - - - - 3.9.3 - - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.23 - - - android - test - - check - - - - - true - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - - - - - bug-check - - - false - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler-plugin.version} - - ${maven.compiler.release} - ${maven.compiler.release} - ${project.build.sourceEncoding} - true - - - - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - ${maven.spotbugs-plugin.version} - - true - - - - - - - diff --git a/samples/semantickernel-concepts/README.md b/samples/semantickernel-concepts/README.md deleted file mode 100644 index a44209028..000000000 --- a/samples/semantickernel-concepts/README.md +++ /dev/null @@ -1,445 +0,0 @@ -# Semantic Kernel Java Version Doc -The purpose of this article is to help you quickly grasp the key concepts in Semantic Kernel and get started quickly. - - -In Semantic Kernel Java, the **builder pattern** is extensively used. If you are not familiar with the builder pattern, I recommend you check out: [Builder Design Pattern](https://refactoring.guru/design-patterns/builder) - -All the code examples below are from `samples/semantickernel-concepts/semantickernel-syntax-examples`. - - -## How to Define an AI Service? - -```java -ChatCompletionService chatCompletionService = ChatCompletionService.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-3.5-turbo-0613") - .withServiceId("fridayChatGeneration") - .build(); -``` - -## How to Use an AI Service? - -- Retrieve the AI Service from the Kernel - - ```java - ChatCompletionService service = kernel.getService(ChatCompletionService.class); - ``` - -- Directly call `service.getChatMessageContentsAsync` to get the LLM response - - ```java - ChatCompletionService service = kernel.getService(ChatCompletionService.class); - var chatHistory = new ChatHistory(systemMessage); - chatHistory.addUserMessage(userMessage); - var answer = service.getChatMessageContentsAsync(chatHistory, kernel, null).block(); - ``` - -## How to Define a KernelBuilder? - -The `KernelBuilder` is a builder used to create and configure a new `Kernel` with necessary services and plugins. - -```java -ChatCompletionService chatCompletionService = ChatCompletionService.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-3.5-turbo-0613") - .withServiceId("fridayChatGeneration") - .build(); - -return Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService); -``` - -## How to Define a Kernel? - -A `Kernel` is created using the `KernelBuilder`, where various services and plugins are configured via `withXXX()`. - -Create a Kernel using `KernelBuilder` and configure the necessary parameters - -```java -Kernel kernel = Kernel.builder() - .withPlugin(myPlugin) - .withAIService(openAiChatService) - .withServiceSelector() - .build(); -``` - -## How to Define a KernelPlugin? - -1. Define a custom class - -2. Construct using `KernelPluginFactory` - -```java -public static class Time { - - @DefineKernelFunction(name = "date") - public String date() { - System.out.println("date is called"); - Date now = new Date(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - return dateFormat.format(now); - } - - @DefineKernelFunction(name = "time") - public String time() { - System.out.println("time is called"); - Date now = new Date(); - SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); - return timeFormat.format(now); - } -} - -KernelPlugin time = KernelPluginFactory.createFromObject(new Time(), "time"); -``` - -## How to Define a KernelFunction? - -### Native function - -A native function in Semantic Kernel performs precise tasks like data retrieval, time checks, and complex math, which large language models (LLMs) may make mistake. Native functions are written in code and ensure accuracy. In contrast, LLMs offer flexibility, generality, and creativity, excelling in generating and predicting text. Combining both leverages their respective strengths for optimal performance. -For more details, refer to [Microsoft Documentation on Kernel Functions.](https://learn.microsoft.com/en-us/semantic-kernel/agents/plugins/using-the-kernelfunction-decorator?tabs=Csharp) - -Here’s an example of how to define a native kernel function: -```java -public class TextPlugin { - @DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase") - public String uppercase(@KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) { - return text.toUpperCase(Locale.ROOT); - } -} -``` - -### Inline function - -To create a inline KernelFunction from a prompt, you can use either of the following methods, which are equivalent: -- `KernelFunctionFromPrompt.builder().withTemplate(promptTemplate).build();` -- `KernelFunction.createFromPrompt(message).build();` - - -#### `KernelFunctionFromPrompt.builder().withTemplate(promptTemplate).build();` - -```java -String promptTemplate = """ - Generate a creative reason or excuse for the given event. - Be creative and be funny. Let your imagination run wild. - - Event: I am running late. - Excuse: I was being held ransom by giraffe gangsters. - - Event: I haven't been to the gym for a year - Excuse: I've been too busy training my pet dragon. - - Event: {{$input}} -""".stripIndent(); - -var excuseFunction = KernelFunctionFromPrompt.builder() - .withTemplate(promptTemplate) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withTemperature(0.4) - .withTopP(1) - .withMaxTokens(500) - .withUser("bx-h") - .build() - ) - .withName("ExcuseGeneratorFunction") - .build(); -``` - -#### `KernelFunction.createFromPrompt(message).build();` - -```java -var message = "Translate this date " + date + " to French format"; -var fixedFunction = KernelFunction - .createFromPrompt(message) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(100) - .build()) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .withName("translator") - .build(); -``` - - -The `SEMANTIC_KERNEL_TEMPLATE_FORMAT` corresponds to the '**semantic-kernel**' rendering engine, which uses the syntax `{{$variable}}` for variables. - -Another rendering engine is **'handlebars'**, which uses the syntax `{{variable}}`. -Here's an example of how to use both: - -```java - runPrompt(kernel, - "semantic-kernel", - "Hello AI, my name is {{$name}}. What is the origin of my name?", - templateFactory); - - runPrompt(kernel, - "handlebars", - "Hello AI, my name is {{name}}. What is the origin of my name?", - templateFactory); -``` -The `runPrompt` method is defined as follows: -```java - public static void runPrompt(Kernel kernel, String templateFormat, String prompt, - PromptTemplateFactory templateFactory) { - var function = new KernelFunctionFromPrompt.Builder<>() - .withTemplate(prompt) - .withTemplateFormat(templateFormat) - .withPromptTemplateFactory(templateFactory) - .build(); - - var arguments = KernelFunctionArguments.builder() - .withVariable("name", "Bob") - .build(); - - var result = kernel.invokeAsync(function).withArguments(arguments).block(); - System.out.println(result.getResult()); - } -``` -For more information, please refer to the following resources: -- [Microsoft Documentation on Prompt Template Syntax](https://learn.microsoft.com/en-us/semantic-kernel/prompts/prompt-template-syntax) -- [Microsoft Devblogs on Using Handlebars Planner in Semantic Kernel](https://devblogs.microsoft.com/semantic-kernel/using-handlebars-planner-in-semantic-kernel/) - -### Configuration file - -Define a function from a configuration file (json) - -```java -var prompt = "Hello AI, what can you do for me?"; -String configPayload = """ - { - "schema": 1, - "name": "HelloAI", - "description": "Say hello to an AI", - "type": "completion", - "completion": { - "max_tokens": 256, - "temperature": 0.5, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - } - } -""".stripIndent(); - -PromptTemplateConfig promptConfig = PromptTemplateConfig - .parseFromJson(configPayload) - .copy() - .withTemplate(prompt) - .build(); - -var func = KernelFunction - .createFromPrompt(promptConfig) - .build(); -``` - -## How to Define a KernelFunctionArguments? - -```java -KernelFunctionArguments.builder().withVariable("input", "Jupiter").build(); -``` - -This can also be done as: - -```java -KernelFunctionArguments.builder().withInput("Jupiter").build(); -``` - -## How to Call a KernelFunction? - -- Direct call: - -```java -TextPlugin text = new TextPlugin(); -return text.uppercase("ciao!"); -``` - -- Invoke via `Kernel.invokeAsync(KernelFunction)` - -```java -Kernel kernel = Kernel.builder().build(); -KernelPlugin kernelPlugin = KernelPluginFactory.createFromObject(new StaticTextPlugin(), "text"); -KernelFunctionArguments arguments = KernelFunctionArguments.builder() - .withVariable("input", "Today is: ") - .withVariable("day", "Monday") - .build(); - -return kernel.invokeAsync(kernelPlugin.get("AppendDay")) - .withArguments(arguments) - .block() - .getResult(); -``` - -OR: - -```java -var result = kernel - .invokeAsync(excuseFunction) - .withArguments( - KernelFunctionArguments.builder() - .withInput("I missed the F1 final race") - .build() - ) - .block(); -``` - -## How to Define a PromptTemplate? - -The purpose of a prompt template is to: - -- Render the prompt -- Be passed as a parameter to `createFromPrompt()` to construct `KernelFunction` - -### Using `KernelPromptTemplateFactory.tryCreate(PromptTemplateConfig)` - -1. Define the prompt template - -2. Create using `KernelPromptTemplateFactory()` - -```java -String functionDefinition = """ - Today is: {{time.date}} - Current time is: {{time.time}} - - Answer the following questions using JSON syntax, including the data used. - Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)? - Is it weekend time (weekend/not weekend)? -"""; - -PromptTemplate promptTemplate = new KernelPromptTemplateFactory().tryCreate( - PromptTemplateConfig - .builder() - .withTemplate(functionDefinition) - .build() -); -``` - -### Create using `PromptTemplateFactory.build` - -```java -String systemPromptTemplate = "..."; -PromptTemplate promptTemplate = PromptTemplateFactory.build( - PromptTemplateConfig - .builder() - .withTemplate(systemPromptTemplate) - .build() -); -``` - -## How to Render a Prompt Without Sending an LLM Query? - -```java -var renderedPrompt = promptTemplate.renderAsync(kernel, KernelFunctionArguments, InvocationContext).block(); -System.out.println(renderedPrompt); -``` - -## Hooks - -Hooks are functions triggered in specific situations attached to the kernel. - -- **Global Registration**: If added to `kernel.getGlobalKernelHooks()`, it is globally effective - - ```java - kernel.getGlobalKernelHooks().addHook("hookName", KernelHook); - ``` - -- **Single Call Registration**: If passed as a parameter in `invokeAsync`, it is effective for that call only - - ```java - KernelHooks kernelHooks = new KernelHooks(); - kernelHooks.addPreChatCompletionHook(...); - - var result = kernel.invokeAsync(writerFunction) - .withArguments(KernelFunctionArguments.builder().build()) - .addKernelHooks(kernelHooks) - .block(); - ``` - -### FunctionInvokingHook - -Triggered before function call. - -```java -FunctionInvokingHook preHook = event -> { - System.out.println(event.getFunction().getName() + " : Pre Execution Handler - Triggered"); - return event; -}; -kernel.getGlobalKernelHooks().addHook("", preHook); -``` - -### FunctionInvokedHook - -Triggered after function call - -```java -FunctionInvokedHook hook = event -> { - String result = (String) event.getResult().getResult(); - System.out.println(event.getFunction().getName() + " : Modified result via FunctionInvokedHook: " + result); - result = result.replaceAll("[aeiouAEIOU0-9]", "*"); - - return new FunctionInvokedEvent( - event.getFunction(), - event.getArguments(), - new FunctionResult<>(ContextVariable.of(result), event.getResult().getMetadata(), result) - ); -}; -kernel.getGlobalKernelHooks().addHook(hook); -``` - -### PromptRenderingHook - -```java -PromptRenderingHook myRenderingHandler = event -> { - System.out.println(event.getFunction().getName() + " : Triggered PromptRenderingHook"); - event.getArguments().put("style", ContextVariable.of("Seinfeld")); - return event; -}; -``` - -### PromptRenderedHook - -```java -PromptRenderedHook myRenderedHandler = event -> { - System.out.println(event.getFunction().getName() + " : Triggered PromptRenderedHook"); - String prompt = event.getPrompt() + "\nUSE SHORT, CLEAR, COMPLETE SENTENCES."; - return new PromptRenderedEvent(event.getFunction(), event.getArguments(), prompt); -}; -``` - -> `PromptRenderingHook` and `PromptRenderedHook` are triggered only at the start of a conversation. They won't trigger during multiple tool calls. To trigger at every LLM interaction, use `ChatCompletionsHook` - -### PreChatCompletionHook - -Add a pre-chat completion hook to add instructions before ChatCompletion. - -```java -kernel.getGlobalKernelHooks().addPreChatCompletionHook(event -> { - ChatCompletionsOptions options = event.getOptions(); - List messages = options.getMessages(); - messages = new ArrayList<>(messages); - messages.add(new ChatRequestSystemMessage("Use upper case text when responding to the prompt.")); - System.out.println("------- Triggered before ChatCompletion -------"); - System.out.println("---- Added: Use upper case text when responding to the prompt. ----"); - for (ChatRequestMessage msg : messages) { - System.out.println(msg); - } - - return new PreChatCompletionEvent( - PreChatCompletionHook.cloneOptionsWithMessages(options, messages) - ); -}); -``` - -### PostChatCompletionHook - -Add a post-chat completion hook to adjust the output format - -```java -kernel.getGlobalKernelHooks().addPostChatCompletionHook(event -> { - System.out.println("------- Triggered after ChatCompletion -------"); - System.out.println("--- Output ChatCompletion and id ----"); - System.out.println("Chat completion"); - System.out.println("Id: " + event.getChatCompletions().getId()); - return event; -}); -``` \ No newline at end of file diff --git a/samples/semantickernel-concepts/pom.xml b/samples/semantickernel-concepts/pom.xml deleted file mode 100644 index 0b51d1255..000000000 --- a/samples/semantickernel-concepts/pom.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-concepts - pom - semantickernel-concepts - - - semantickernel-syntax-examples - - diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/README.md b/samples/semantickernel-concepts/semantickernel-syntax-examples/README.md deleted file mode 100644 index 586e12695..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# Java Samples - -## TL;DR - -Run with: - -```shell -# AZURE: -OPENAI_CLIENT_TYPE=AZURE_OPEN_AI \ -AZURE_OPEN_AI_KEY="my-key" \ -AZURE_OPEN_AI_ENDPOINT="endpoint url" \ -../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode - -# OPENAI: -OPENAI_CLIENT_TYPE=OPENAI \ -OPEN_AI_KEY="my-key" \ -OPEN_AI_ORGANIZATION_ID="organisation id" \ -../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -# Compile - -These samples can be compiled via: - -```shell - ../../mvnw clean package -``` - -They can then be run by: - -```shell -../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -# Configuration - -By default, the samples will use the Open AI client, but you can also use the Azure Open AI client. - -## Open AI client type - -You can define the provider of Open AI (openai.com or Azure), this can be done by setting the `OPENAI_CLIENT_TYPE` -property or environment variable to either [`OPENAI`](https://platform.openai.com/) -or [`AZURE_OPEN_AI`](https://learn.microsoft.com/azure/cognitive-services/openai/). By default, the samples will use the -Open AI client. - -```shell -OPENAI_CLIENT_TYPE=OPEN_AI ../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode - -OR - - ../../mvnw exec:java -DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI -Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -## Client Settings -The samples search for the client settings in the following order: -1. Properties file whose location is defined by the `CONF_PROPERTIES` property or environment variable. -1. System properties defined on the command line. -1. Environment variables. -1. Properties file at `samples/conf.properties`. -1. Properties file at `~/.sk/conf.properties`. - -## Properties File - -You can set the location of a properties file, by setting the `CONF_PROPERTIES` property or environment variable, ie: - -```shell -CONF_PROPERTIES=my.properties \ -OPENAI_CLIENT_TYPE=OPEN_AI \ -../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode - -OR - -../../mvnw exec:java \ --DCONF_PROPERTIES=my.properties \ --DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \ --Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -A properties file looks as follows: - -```properties -# If using openai.com -client.openai.key:"my-key" -client.openai.organizationid:"my-org-id" -# if using Azure Open AI -client.azureopenai.key:"my-key" -client.azureopenai.endpoint:"url of azure openai endpoint" -client.azureopenai.deploymentname:"deployment name" -``` - -## System Properties - -As an alternative to providing the key/endpoint properties via a file, you can set them directly via system properties, -ie: - -```shell -# OpenAI -../../mvnw exec:java \ --DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \ --Dclient.openai.key="my-key" \ --Dclient.openai.organizationid="my-org-id" \ --Dsample=Example04_CombineLLMPromptsAndNativeCode - -# Azure -../../mvnw exec:java \ --DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \ --Dclient.azureopenai.key="my-key" \ --Dclient.azureopenai.endpoint="url of azure openai endpoint" \ --Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -## Environment variables - -Alternative to properties, you can set environment variables as follows: - -```shell -# AZURE: -OPENAI_CLIENT_TYPE=AZURE_OPEN_AI \ -AZURE_OPEN_AI_KEY="my-key" \ -AZURE_OPEN_AI_ENDPOINT="endpoint url" \ -../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode - -# OPENAI: -OPENAI_CLIENT_TYPE=OPEN_AI \ -OPEN_AI_KEY="my-key" \ -OPEN_AI_ORGANIZATION_ID="organisation id" \ -../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode -``` - -## Managed Identity and Azure CLI Credentials (Azure only) - -The `credentialtype` setting (i.e `client.openai.credentialtype`): - -- `managed_identity`: will attempt to obtain credentials via Azure's managed identity. -- `azure_cli`: will attempt to obtain credentials via Azure's CLI, to use this you must have logged in to the az client - for instance by running `az login`. - -To use either of these settings, the `azure-identity` dependency must be available to the application. Additionally, you -must have the "Cognitive Services User" role assigned to your identity. - diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml deleted file mode 100644 index bd5b298ce..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml +++ /dev/null @@ -1,243 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-concepts - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-syntax-examples - Semantic Kernel Samples - Sample code for using the Semantic Kernel project - jar - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - io.opentelemetry.instrumentation - opentelemetry-reactor-3.1 - 2.9.0-alpha - - - com.microsoft.semantic-kernel - semantickernel-api - - - - com.microsoft.semantic-kernel - semantickernel-data-azureaisearch - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-data-redis - - - - com.microsoft.semantic-kernel - semantickernel-agents-core - - - - com.microsoft.semantic-kernel - semantickernel-experimental - - - - com.microsoft.semantic-kernel - semantickernel-aiservices-huggingface - - - - org.apache.logging.log4j - log4j-api - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.azure - azure-identity - - - redis.clients - jedis - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - com.microsoft.semantic-kernel - semantickernel-aiservices-google - - - com.microsoft.semantic-kernel - semantickernel-text-splitter-plugin - ${project.version} - - - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-localization - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - - org.apache.pdfbox - pdfbox - 3.0.3 - - - - com.google.cloud - google-cloud-vertexai - 1.6.0 - compile - - - - com.mysql - mysql-connector-j - 9.0.0 - - - com.github.victools - jsonschema-generator - - - com.github.victools - jsonschema-module-jackson - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-learn-resources - ${project.version} - compile - - - com.microsoft.semantic-kernel - semantickernel-data-postgres - ${project.version} - compile - - - com.microsoft.semantic-kernel - semantickernel-data-oracle - ${project.version} - compile - - - - - - bug-check - - - false - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - true - - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - - org.codehaus.mojo - exec-maven-plugin - - - run-sample - - java - - - - - com.microsoft.semantickernel.samples.syntaxexamples.${sample} - false - - - - - diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/connectors/web/bing/BingConnector.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/connectors/web/bing/BingConnector.java deleted file mode 100644 index f179b1fe0..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/connectors/web/bing/BingConnector.java +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.connectors.web.bing; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; - -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.HttpMethod; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.HttpResponse; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.connectors.WebSearchEngineConnector; -import com.microsoft.semantickernel.exceptions.SKException; - -import reactor.core.publisher.Mono; - -public class BingConnector implements WebSearchEngineConnector { - - private static String BING_SEARCH_URL; - static { - String bingSearchUrl = System.getProperty("bing.search.url"); - if (bingSearchUrl == null || bingSearchUrl.isEmpty()) - bingSearchUrl = System.getenv("BING_SEARCH_URL"); - if (bingSearchUrl == null || bingSearchUrl.isEmpty()) - bingSearchUrl = "https://api.bing.microsoft.com/v7.0/search"; - BING_SEARCH_URL = bingSearchUrl; - } - - private static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key"; - private static final HttpHeaderName OCP_APIM_SUBSCRIPTION_KEY_HEADER = HttpHeaderName - .fromString(OCP_APIM_SUBSCRIPTION_KEY); - - private static class BingSearchResponse { - private final WebPages webPages; - - @JsonCreator - public BingSearchResponse( - @JsonProperty("webPages") WebPages webPages) { - this.webPages = webPages; - } - - public WebPages getWebPages() { - return webPages; - } - } - - private static class WebPages { - private final WebPage[] value; - - @JsonCreator - public WebPages( - @JsonProperty("value") BingWebPage[] value) { - this.value = value; - } - - public WebPage[] getValue() { - return value; - } - } - - public static class BingWebPage implements WebPage { - private final String name; - private final String url; - private final String snippet; - - @JsonCreator - public BingWebPage( - @JsonProperty("name") String name, - @JsonProperty("url") String url, - @JsonProperty("snippet") String snippet) { - this.name = name; - this.url = url; - this.snippet = snippet; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getUrl() { - return url; - } - - @Override - public String getSnippet() { - return snippet; - } - } - - private final String apiKey; // TODO: secure this - private final HttpClient httpClient; - - public BingConnector(String apiKey, HttpClient httpClient) { - this.apiKey = apiKey; - this.httpClient = httpClient; - } - - public BingConnector(String apiKey) { - this(apiKey, HttpClient.createDefault()); - } - - @Override - public Mono> searchAsync(String query, int count, int offset) { - - if (count <= 0 || 50 <= count) - throw new IllegalArgumentException("count must be between 1 and 50"); - if (offset < 0) - throw new IllegalArgumentException("offset must be greater than or equal to 0"); - - HttpRequest request = new HttpRequest(HttpMethod.GET, searchUrl(query, count, offset)); - request.setHeader(OCP_APIM_SUBSCRIPTION_KEY_HEADER, apiKey); - - return httpClient.send(request).flatMap(BingConnector::handleResponse); - - } - - private static String searchUrl(String query, int count, int offset) { - - try { - query = URLEncoder.encode(query, StandardCharsets.UTF_8.toString()); - } catch (UnsupportedEncodingException e) { - // ignored - UTF-8 is always supported - } - - String url = String.format("%s?q=%s&count=%s&offset=%s", - BING_SEARCH_URL, query, Integer.toString(count), Integer.toString(offset)); - return url; - } - - private static Mono> handleResponse(HttpResponse response) { - return response.getBodyAsString() - .map(body -> { - if (body == null || body.isEmpty()) - return null; - try { - ObjectMapper objectMapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES, - false); - - BingSearchResponse bingSearchResponse = objectMapper.readValue(body, - BingSearchResponse.class); - if (bingSearchResponse.getWebPages() != null - && bingSearchResponse.getWebPages().getValue() != null) { - return Arrays.asList(bingSearchResponse.getWebPages().getValue()); - } - } catch (JsonProcessingException e) { - throw new SKException(e.getMessage(), e); - } - return null; - }); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/App.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/App.java deleted file mode 100644 index 21a4b1c8c..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/App.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.demos.lights; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.google.gson.Gson; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationContext.Builder; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.util.List; -import java.util.Scanner; - -public class App { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - public static void main(String[] args) throws Exception { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // Create your AI service client - ChatCompletionService chatService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - // Create a plugin (the LightsPlugin class is defined separately) - KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(), - "LightsPlugin"); - - // Create a kernel with Azure OpenAI chat completion and plugin - Kernel.Builder builder = Kernel.builder(); - builder.withAIService(ChatCompletionService.class, chatService); - builder.withPlugin(lightPlugin); - // Build the kernel - Kernel kernel = builder.build(); - - ChatCompletionService chatCompletionService = kernel.getService( - ChatCompletionService.class); - - ContextVariableTypes - .addGlobalConverter(new LightModelTypeConverter()); - - KernelHooks hook = new KernelHooks(); - - hook.addPreToolCallHook((context) -> { - System.out.println("Pre-tool call hook"); - return context; - }); - - hook.addPreChatCompletionHook( - (context) -> { - System.out.println("Pre-chat completion hook"); - return context; - }); - - hook.addPostChatCompletionHook( - (context) -> { - System.out.println("Post-chat completion hook"); - return context; - }); - - kernel.getGlobalKernelHooks().addHooks(hook); - - // Enable planning - InvocationContext invocationContext = new Builder() - .withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withContextVariableConverter(new LightModelTypeConverter()) - .build(); - - // Create a history to store the conversation - ChatHistory history = new ChatHistory(); - // Initiate a back-and-forth chat - Scanner scanner = new Scanner(System.in); - String userInput; - do { - // Collect user input - System.out.print("User > "); - userInput = scanner.nextLine(); - // Add user input - history.addUserMessage(userInput); - List> results = chatCompletionService.getChatMessageContentsAsync( - history, kernel, invocationContext).block(); - for (ChatMessageContent result : results) { - // Print the results - if (result.getAuthorRole() == AuthorRole.ASSISTANT && result.getContent() != null) { - System.out.println("Assistant > " + result); - } - // Add the message from the agent to the chat history - history.addMessage(result); - } - } while (userInput != null && !userInput.isEmpty()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModel.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModel.java deleted file mode 100644 index e7958507b..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModel.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.demos.lights; - -import com.fasterxml.jackson.annotation.JsonPropertyDescription; - -public class LightModel { - - @JsonPropertyDescription("The unique identifier of the light") - private int id; - - @JsonPropertyDescription("The name of the light") - private String name; - - @JsonPropertyDescription("The state of the light") - private Boolean isOn; - - public LightModel(int id, String name, Boolean isOn) { - this.id = id; - this.name = name; - this.isOn = isOn; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Boolean getIsOn() { - return isOn; - } - - public void setIsOn(Boolean isOn) { - this.isOn = isOn; - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModelTypeConverter.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModelTypeConverter.java deleted file mode 100644 index 2752eb624..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightModelTypeConverter.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.demos.lights; - -import com.google.gson.Gson; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; - -public class LightModelTypeConverter extends ContextVariableTypeConverter { - private static final Gson gson = new Gson(); - - public LightModelTypeConverter() { - super( - LightModel.class, - obj -> { - if (obj instanceof String) { - return gson.fromJson((String) obj, LightModel.class); - } else { - return gson.fromJson(gson.toJson(obj), LightModel.class); - } - }, - (types, lightModel) -> gson.toJson(lightModel), - json -> gson.fromJson(json, LightModel.class)); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightsPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightsPlugin.java deleted file mode 100644 index 398a8d16d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/demos/lights/LightsPlugin.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.demos.lights; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class LightsPlugin { - - // Mock data for the lights - private final List lights = new ArrayList<>(); - - public LightsPlugin() { - lights.add(new LightModel(1, "Table Lamp", false)); - lights.add(new LightModel(2, "Porch light", false)); - lights.add(new LightModel(3, "Chandelier", true)); - } - - @DefineKernelFunction(name = "get_lights", description = "Gets a list of lights and their current state") - public List getLights() { - System.out.println("Getting lights"); - return lights; - } - - @DefineKernelFunction(name = "add_light", description = "Adds a new light") - public String addLight( - @KernelFunctionParameter(name = "newLight", description = "new Light Details", type = LightModel.class) LightModel light) { - if (light != null) { - System.out.println("Adding light " + light.getName()); - lights.add(light); - return "Light added"; - } - return "Light failed to added"; - } - - @DefineKernelFunction(name = "change_state", description = "Changes the state of the light") - public LightModel changeState( - @KernelFunctionParameter(name = "id", description = "The ID of the light to change", type = int.class) int id, - @KernelFunctionParameter(name = "isOn", description = "The new state of the light", type = boolean.class) boolean isOn) { - System.out.println("Changing light " + id + " " + isOn); - Optional light = lights.stream() - .filter(l -> l.getId() == id) - .findFirst(); - - if (light.isEmpty()) { - throw new IllegalArgumentException("Light not found"); - } - light.get().setIsOn(isOn); - - return light.get(); - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java deleted file mode 100644 index f61d1d873..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.text.TextChunker; -import java.util.List; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -///

-/// Semantic plugin that enables conversations summarization. -/// -public class ConversationSummaryPlugin { - - /// - /// The max tokens to process in a single prompt function call. - /// - private static final int MaxTokens = 1024; - - private KernelFunction summarizeConversationFunction; - private KernelFunction conversationActionItemsFunction; - private KernelFunction conversationTopicsFunction; - - /// - /// Initializes a new instance of the class. - /// - public ConversationSummaryPlugin() { - PromptExecutionSettings settings = PromptExecutionSettings.builder() - .withMaxTokens(MaxTokens) - .withTemperature(0.1) - .withTopP(0.5) - .build(); - - this.summarizeConversationFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.SummarizeConversationDefinition) - .withDefaultExecutionSettings(settings) - .withName("summarizeConversation") - .withDescription( - "Given a section of a conversation transcript, summarize the part of the conversation.") - .build(); - - this.conversationActionItemsFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.GetConversationActionItemsDefinition) - .withDefaultExecutionSettings(settings) - .withName("conversationActionItems") - .withDescription("Given a section of a conversation transcript, identify action items.") - .build(); - - this.conversationTopicsFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.GetConversationTopicsDefinition) - .withDefaultExecutionSettings(settings) - .withName("conversationTopics") - .withDescription( - "Analyze a conversation transcript and extract key topics worth remembering.") - .build(); - } - - private static Mono processAsync(KernelFunction func, String input, - Kernel kernel) { - List lines = TextChunker.splitPlainTextLines(input, MaxTokens); - List paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens); - - return Flux.fromIterable(paragraphs) - .concatMap(paragraph -> { - // The first parameter is the input text. - return func.invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withInput(paragraph) - .build()) - .withResultType( - ContextVariableTypes.getGlobalVariableTypeForClass(String.class)); - }) - .reduce("", (acc, next) -> { - return acc + "\n" + next.getResult(); - }); - } - - /// - /// Given a long conversation transcript, summarize the conversation. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, summarize the conversation.", name = "SummarizeConversation", returnType = "java.lang.String") - public Mono SummarizeConversationAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.summarizeConversationFunction, input, kernel); - } - - /// - /// Given a long conversation transcript, identify action items. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, identify action items.", name = "GetConversationActionItems", returnType = "java.lang.String") - public Mono GetConversationActionItemsAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.conversationActionItemsFunction, input, kernel); - } - - /// - /// Given a long conversation transcript, identify topics. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, identify topics worth remembering.", name = "GetConversationTopics", returnType = "java.lang.String") - - public Mono GetConversationTopicsAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.conversationTopicsFunction, input, kernel); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java deleted file mode 100644 index 1f9a7ce34..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -// -public class MathPlugin { - // - - // - @DefineKernelFunction(name = "sqrt", description = "Take the square root of a number") - public static double sqrt( - @KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) { - return Math.sqrt(number1); - } - // - - @DefineKernelFunction(name = "add", description = "Add two numbers") - public static double add( - @KernelFunctionParameter(name = "number1", description = "The first number to add", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to add", type = double.class) double number2) { - return number1 + number2; - } - - @DefineKernelFunction(name = "subtract", description = "Subtract two numbers") - public static double subtract( - @KernelFunctionParameter(name = "number1", description = "The first number to subtract from", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to subtract away", type = double.class) double number2) { - return number1 - number2; - } - - @DefineKernelFunction(name = "multiply", description = "Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.") - public static double multiply( - @KernelFunctionParameter(name = "number1", description = "The first number to multiply", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to multiply", type = double.class) double number2) { - return number1 * number2; - } - - @DefineKernelFunction(name = "divide", description = "Divide two numbers") - public static double divide( - @KernelFunctionParameter(name = "number1", description = "The first number to divide from", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to divide by", type = double.class) double number2) { - return number1 / number2; - } - - @DefineKernelFunction(name = "power", description = "Raise a number to a power") - public static double power( - @KernelFunctionParameter(name = "number1", description = "The number to raise", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The power to raise the number to", type = double.class) double number2) { - return Math.pow(number1, number2); - } - - @DefineKernelFunction(name = "log", description = "Take the log of a number") - public static double log( - @KernelFunctionParameter(name = "number1", description = "The number to take the log of", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The base of the log", type = double.class) double number2) { - return Math.log(number1) / Math.log(number2); - } - - @DefineKernelFunction(name = "round", description = "Round a number to the target number of decimal places") - public static double round( - @KernelFunctionParameter(name = "number1", description = "The number to round", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The number of decimal places to round to", type = double.class) int number2) { - return Math.round(number1 * Math.pow(10, number2)) / Math.pow(10, number2); - } - - @DefineKernelFunction(name = "abs", description = "Take the absolute value of a number") - public static double abs( - @KernelFunctionParameter(name = "number1", description = "The number to take the absolute value of", type = double.class) double number1) { - return Math.abs(number1); - } - - @DefineKernelFunction(name = "floor", description = "Take the floor of a number") - public static double floor( - @KernelFunctionParameter(name = "number1", description = "The number to take the floor of", type = double.class) double number1) { - return Math.floor(number1); - } - - @DefineKernelFunction(name = "ceiling", description = "Take the ceiling of a number") - public static double ceiling( - @KernelFunctionParameter(name = "number1", description = "The number to take the ceiling of", type = double.class) double number1) { - return Math.ceil(number1); - } - - @DefineKernelFunction(name = "sin", description = "Take the sine of a number") - public static double sin( - @KernelFunctionParameter(name = "number1", description = "The number to take the sine of", type = double.class) double number1) { - return Math.sin(number1); - } - - @DefineKernelFunction(name = "cos", description = "Take the cosine of a number") - public static double cos( - @KernelFunctionParameter(name = "number1", description = "The number to take the cosine of", type = double.class) double number1) { - return Math.cos(number1); - } - - @DefineKernelFunction(name = "tan", description = "Take the tangent of a number") - public static double tan( - @KernelFunctionParameter(name = "number1", description = "The number to take the tangent of", type = double.class) double number1) { - return Math.tan(number1); - } - - @DefineKernelFunction(name = "asin", description = "Take the arcsine of a number") - public static double asin( - @KernelFunctionParameter(name = "number1", description = "The number to take the arcsine of", type = double.class) double number1) { - return Math.asin(number1); - } - - @DefineKernelFunction(name = "acos", description = "Take the arccosine of a number") - public static double acos( - @KernelFunctionParameter(name = "number1", description = "The number to take the arccosine of", type = double.class) double number1) { - return Math.acos(number1); - } - - @DefineKernelFunction(name = "atan", description = "Take the arctangent of a number") - public static double atan( - @KernelFunctionParameter(name = "number1", description = "The number to take the arctangent of", type = double.class) double number1) { - return Math.atan(number1); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java deleted file mode 100644 index 22c51f383..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -public class PromptFunctionConstants { - - public static final String SummarizeConversationDefinition = """ - BEGIN CONTENT TO SUMMARIZE: - {{$INPUT}} - - END CONTENT TO SUMMARIZE. - - Summarize the conversation in 'CONTENT TO SUMMARIZE', identifying main points of discussion and any conclusions that were reached. - Do not incorporate other general knowledge. - Summary is in plain text, in complete sentences, with no markup or tags. - - BEGIN SUMMARY: - """ - .stripIndent(); - - public static final String GetConversationActionItemsDefinition = """ - You are an action item extractor. You will be given chat history and need to make note of action items mentioned in the chat. - Extract action items from the content if there are any. If there are no action, return nothing. If a single field is missing, use an empty string. - Return the action items in json. - - Possible statuses for action items are: Open, Closed, In Progress. - - EXAMPLE INPUT WITH ACTION ITEMS: - - John Doe said: "I will record a demo for the new feature by Friday" - I said: "Great, thanks John. We may not use all of it but it's good to get it out there." - - EXAMPLE OUTPUT: - { - "actionItems": [ - { - "owner": "John Doe", - "actionItem": "Record a demo for the new feature", - "dueDate": "Friday", - "status": "Open", - "notes": "" - } - ] - } - - EXAMPLE INPUT WITHOUT ACTION ITEMS: - - John Doe said: "Hey I'm going to the store, do you need anything?" - I said: "No thanks, I'm good." - - EXAMPLE OUTPUT: - { - "action_items": [] - } - - CONTENT STARTS HERE. - - {{$INPUT}} - - CONTENT STOPS HERE. - - OUTPUT: - """ - .stripIndent(); - - public static final String GetConversationTopicsDefinition = """ - Analyze the following extract taken from a conversation transcript and extract key topics. - - Topics only worth remembering. - - Be brief. Short phrases. - - Can use broken English. - - Conciseness is very important. - - Topics can include names of memories you want to recall. - - NO LONG SENTENCES. SHORT PHRASES. - - Return in JSON - [Input] - My name is Macbeth. I used to be King of Scotland, but I died. My wife's name is Lady Macbeth and we were married for 15 years. We had no children. Our beloved dog Toby McDuff was a famous hunter of rats in the forest. - My tragic story was immortalized by Shakespeare in a play. - [Output] - { - "topics": [ - "Macbeth", - "King of Scotland", - "Lady Macbeth", - "Dog", - "Toby McDuff", - "Shakespeare", - "Play", - "Tragedy" - ] - } - +++++ - [Input] - {{$INPUT}} - [Output]""" - .stripIndent(); -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/TimePlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/TimePlugin.java deleted file mode 100644 index 45ca95805..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/TimePlugin.java +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -import com.microsoft.semantickernel.samples.util.LocaleParser; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.TextStyle; -import java.util.Locale; - -public class TimePlugin { - - public static final String DAY_MONTH_DAY_YEAR = "EEEE, MMMM d, yyyy"; - - /** - * Get the current date and time for the system default timezone. - * - * @return a ZonedDateTime object with the current date and time. - */ - public ZonedDateTime now() { - return ZonedDateTime.now(ZoneId.systemDefault()); - } - - /** - * Get the current date. - * - *

Example: {{time.date}} => Sunday, January 12, 2025 - * - * @return The current date. - */ - @DefineKernelFunction(name = "date", description = "Get the current date") - public String date( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - // Example: Sunday, 12 January, 2025 - return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR) - .withLocale(parseLocale(locale)) - .format(now()); - } - - /** - * Get the current time. - * - *

Example: {{time.time}} => 9:15:00 AM - * - * @return The current time. - */ - @DefineKernelFunction(name = "time", description = "Get the current time") - public String time( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - // Example: 09:15:07 PM - return DateTimeFormatter.ofPattern("hh:mm:ss a") - .withLocale(parseLocale(locale)) - .format(now()); - } - - /** - * Get the current UTC date and time. - * - *

Example: {{time.utcNow}} => Sunday, January 13, 2025 5:15 AM - * - * @return The current UTC date and time. - */ - @DefineKernelFunction(name = "utcNow", description = "Get the current UTC date and time") - public String utcNow( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a") - .withLocale(parseLocale(locale)) - .format(now().withZoneSameInstant(ZoneOffset.UTC)); - } - - /** - * Get the current date (alias for date() method). - * - *

Example: {{time.today}} => Sunday, January 12, 2025 - * - * @return The current date. - */ - @DefineKernelFunction(name = "today", description = "Get the current date") - public String today( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return date(locale); - } - - /** - * Get the current date and time in the local time zone. - * - *

Example: {{time.now}} => Sunday, January 12, 2025 9:15 AM - * - * @return The current date and time in the local time zone. - */ - @DefineKernelFunction(name = "now", description = "Get the current date and time in the local time zone") - public String now( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a") - .withLocale(parseLocale(locale)) - .format(now()); - } - - /** - * Get the current year. - * - *

Example: {{time.year}} => 2025 - * - * @return The current year. - */ - @DefineKernelFunction(name = "year", description = "Get the current year") - public String year( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("yyyy").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current month name. - * - *

Example: {{time.month}} => January - * - * @return The current month name. - */ - @DefineKernelFunction(name = "month", description = "Get the current month name") - public String month( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("MMMM").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current month number. - * - *

Example: {{time.monthNumber}} => 01 - * - * @return The current month number. - */ - @DefineKernelFunction(name = "monthNumber", description = "Get the current month number") - public String monthNumber( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("MM").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current day of the month. - * - *

Example: {{time.day}} => 12 - * - * @return The current day of the month. - */ - @DefineKernelFunction(name = "day", description = "Get the current day of the month") - public String day( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("d").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current day of the week. - * - *

Example: {{time.dayOfWeek}} => Sunday - * - * @return The current day of the week. - */ - @DefineKernelFunction(name = "dayOfWeek", description = "Get the current day of the week") - public String dayOfWeek( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("EEEE").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current clock hour. - * - *

Example: {{time.hour}} => 9 AM - * - * @return The current clock hour. - */ - @DefineKernelFunction(name = "hour", description = "Get the current clock hour") - public String hour( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("h a").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the current clock 24-hour number. - * - *

Example: {{time.hourNumber}} => 09 - * - * @return The current clock 24-hour number. - */ - @DefineKernelFunction(name = "hourNumber", description = "Get the current clock 24-hour number") - public String hourNumber( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("HH").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the date of offset from today by a provided number of days - * - *

Example: SKContext context = SKBuilders.context().build(); context.setVariable("input", - * "3"); {{time.daysAgo $input}} => Saturday, January 11, 2031 - * - * @param days Number of days to subtract from the current day - * @return The date of offset from today by a provided number of days - */ - @DefineKernelFunction(name = "daysAgo", description = "Get the date of offset from today by a provided number of days") - public String daysAgo( - @KernelFunctionParameter(name = "days", description = "Number of days to offset from today.") String days, - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - int offsetDays = Integer.parseInt(days); - return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR) - .withLocale(parseLocale(locale)) - .format(now().minusDays(offsetDays)); - } - - /** - * Get the date of the last day matching the supplied week day name - * - *

Example: {{time.dateMatchingLastDayName "Monday"}} => Monday, January 6, 2031 - * - * @param dayName Name of the day to match - * @return The date of the last day matching the supplied week day name - */ - @DefineKernelFunction(name = "dateMatchingLastDayName", description = "Get the date of the last day matching the supplied week day name") - public String dateMatchingLastDayName( - @KernelFunctionParameter(name = "dayName", description = "Week name day.") String dayName, - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - ZonedDateTime currentDate = now(); - for (int i = 1; i <= 7; i++) { - currentDate = currentDate.minusDays(1); - String currentDayName = currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, - parseLocale(locale)); - - if (currentDayName.equalsIgnoreCase(dayName)) { - return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR) - .withLocale(parseLocale(locale)) - .format(currentDate); - } - } - throw new IllegalArgumentException("dayName is not recognized"); - } - - /** - * Get the minutes on the current hour. - * - *

Example: {{time.minute}} => 15 - * - * @return The minutes on the current hour. - */ - @DefineKernelFunction(name = "minute", description = "Get the minutes on the current hour") - public String minute( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("mm").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the seconds on the current minute. - * - *

Example: {{time.second}} => 00 - * - * @return The seconds on the current minute. - */ - @DefineKernelFunction(name = "second", description = "Get the seconds on the current minute") - public String second( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("ss").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the local time zone offset from UTC. - * - *

Example: {{time.timeZoneOffset}} => +03:00 - * - * @return The local time zone offset from UTC. - */ - @DefineKernelFunction(name = "timeZoneOffset", description = "Get the local time zone offset from UTC") - public String timeZoneOffset( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - return DateTimeFormatter.ofPattern("XXX").withLocale(parseLocale(locale)).format(now()); - } - - /** - * Get the local time zone name. - * - *

Example: {{time.timeZoneName}} => Pacific Time - * - * @return The local time zone name. - */ - @DefineKernelFunction(name = "timeZoneName", description = "Get the local time zone name") - public String timeZoneName( - @KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) { - ZoneId zoneId = ZoneId.systemDefault(); - return zoneId.getDisplayName(TextStyle.FULL, parseLocale(locale)); - } - - /** - * Parse the locale string into a Locale object. - * - *

By default, it parses using the LocaleParser utility class. - * - * @param locale string - * @return a locale object - */ - protected Locale parseLocale(String locale) { - return LocaleParser.parseLocale(locale); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java deleted file mode 100644 index 0f8065ee1..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.github; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; - -public abstract class GitHubModel { - public final static ObjectMapper objectMapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - @Override - public String toString() { - try { - return objectMapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - public static class User extends GitHubModel { - @JsonProperty("login") - private String login; - @JsonProperty("id") - private long id; - @JsonProperty("name") - private String name; - @JsonProperty("company") - private String company; - @JsonProperty("html_url") - private String url; - - @JsonCreator - public User(@JsonProperty("login") String login, - @JsonProperty("id") long id, - @JsonProperty("name") String name, - @JsonProperty("company") String company, - @JsonProperty("html_url") String url) { - this.login = login; - this.id = id; - this.name = name; - this.company = company; - this.url = url; - } - - public String getLogin() { - return login; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getCompany() { - return company; - } - - public String getUrl() { - return url; - } - } - - public static class Repository extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("full_name") - private String name; - @JsonProperty("description") - private String description; - @JsonProperty("html_url") - private String url; - - @JsonCreator - public Repository(@JsonProperty("id") long id, - @JsonProperty("full_name") String name, - @JsonProperty("description") String description, - @JsonProperty("html_url") String url) { - this.id = id; - this.name = name; - this.description = description; - this.url = url; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public String getUrl() { - return url; - } - - @Override - public String toString() { - try { - return objectMapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - public static class Issue extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("number") - private long number; - @JsonProperty("title") - private String title; - @JsonProperty("state") - private String state; - @JsonProperty("html_url") - private String url; - @JsonProperty("labels") - private Label[] labels; - @JsonProperty("created_at") - private String createdAt; - @JsonProperty("closed_at") - private String closedAt; - - @JsonCreator - public Issue(@JsonProperty("id") long id, - @JsonProperty("number") long number, - @JsonProperty("title") String title, - @JsonProperty("state") String state, - @JsonProperty("html_url") String url, - @JsonProperty("labels") Label[] labels, - @JsonProperty("created_at") String createdAt, - @JsonProperty("closed_at") String closedAt) { - this.id = id; - this.number = number; - this.title = title; - this.state = state; - this.url = url; - this.labels = labels; - this.createdAt = createdAt; - this.closedAt = closedAt; - } - - public long getId() { - return id; - } - - public long getNumber() { - return number; - } - - public String getTitle() { - return title; - } - - public String getState() { - return state; - } - - public String getUrl() { - return url; - } - - public Label[] getLabels() { - return labels; - } - - public String getCreatedAt() { - return createdAt; - } - - public String getClosedAt() { - return closedAt; - } - } - - public static class IssueDetail extends Issue { - @JsonProperty("body") - private String body; - - @JsonCreator - public IssueDetail(@JsonProperty("id") long id, - @JsonProperty("number") long number, - @JsonProperty("title") String title, - @JsonProperty("state") String state, - @JsonProperty("html_url") String url, - @JsonProperty("labels") Label[] labels, - @JsonProperty("created_at") String createdAt, - @JsonProperty("closed_at") String closedAt, - @JsonProperty("body") String body) { - super(id, number, title, state, url, labels, createdAt, closedAt); - this.body = body; - } - - public String getBody() { - return body; - } - } - - public static class Label extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("name") - private String name; - @JsonProperty("description") - private String description; - - @JsonCreator - public Label(@JsonProperty("id") long id, - @JsonProperty("name") String name, - @JsonProperty("description") String description) { - this.id = id; - this.name = name; - this.description = description; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java deleted file mode 100644 index f0bddee10..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.github; - -import reactor.core.publisher.Mono; -import reactor.netty.http.client.HttpClient; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -import java.io.IOException; -import java.util.List; - -public class GitHubPlugin { - public static final String baseUrl = "https://api.github.com"; - private final String token; - - public GitHubPlugin(String token) { - this.token = token; - } - - @DefineKernelFunction(name = "get_user_info", description = "Get user information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$User") - public Mono getUserProfileAsync() { - HttpClient client = createClient(); - - return makeRequestAsync(client, "/user") - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.User.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubUser", e); - } - }); - } - - @DefineKernelFunction(name = "get_repo_info", description = "Get repository information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$Repository") - public Mono getRepositoryAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName) { - HttpClient client = createClient(); - - return makeRequestAsync(client, String.format("/repos/%s/%s", organization, repoName)) - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.Repository.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubRepository", e); - } - }); - } - - @DefineKernelFunction(name = "get_issues", description = "Get issues from GitHub", returnType = "java.util.List") - public Mono> getIssuesAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the organization to retrieve issues for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve issues for") String repoName, - @KernelFunctionParameter(name = "max_results", description = "The maximum number of issues to retrieve", required = false, defaultValue = "10", type = int.class) int maxResults, - @KernelFunctionParameter(name = "state", description = "The state of the issues to retrieve", required = false, defaultValue = "open") String state, - @KernelFunctionParameter(name = "assignee", description = "The assignee of the issues to retrieve", required = false) String assignee) { - HttpClient client = createClient(); - - String query = String.format("/repos/%s/%s/issues", organization, repoName); - query = buildQueryString(query, "state", state); - query = buildQueryString(query, "assignee", assignee); - query = buildQueryString(query, "per_page", String.valueOf(maxResults)); - - return makeRequestAsync(client, query) - .flatMap(json -> { - try { - GitHubModel.Issue[] issues = GitHubModel.objectMapper.readValue(json, - GitHubModel.Issue[].class); - return Mono.just(List.of(issues)); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubIssues", e); - } - }); - } - - @DefineKernelFunction(name = "get_issue_detail_info", description = "Get detail information of a single issue from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$IssueDetail") - public GitHubModel.IssueDetail getIssueDetailAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName, - @KernelFunctionParameter(name = "issue_number", description = "The issue number to retrieve information for", type = int.class) int issueNumber) { - HttpClient client = createClient(); - - return makeRequestAsync(client, - String.format("/repos/%s/%s/issues/%d", organization, repoName, issueNumber)) - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.IssueDetail.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubIssue", e); - } - }).block(); - } - - private HttpClient createClient() { - return HttpClient.create() - .baseUrl(baseUrl) - .headers(headers -> { - headers.add("User-Agent", "request"); - headers.add("Accept", "application/vnd.github+json"); - headers.add("Authorization", "Bearer " + token); - headers.add("X-GitHub-Api-Version", "2022-11-28"); - }); - } - - private static String buildQueryString(String path, String param, String value) { - if (value == null || value.isEmpty() - || value.equals(KernelFunctionParameter.NO_DEFAULT_VALUE)) { - return path; - } - - return path + (path.contains("?") ? "&" : "?") + param + "=" + value; - } - - private Mono makeRequestAsync(HttpClient client, String path) { - return client - .get() - .uri(path) - .responseSingle((res, content) -> { - if (res.status().code() != 200) { - return Mono.error(new IllegalStateException("Request failed: " + res.status())); - } - return content.asString(); - }); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/text/TextPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/text/TextPlugin.java deleted file mode 100644 index 75c49be81..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/text/TextPlugin.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.text; - -import java.util.Locale; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -/** - * TextPlugin provides a set of functions to manipulate strings. - */ -public class TextPlugin { - - @DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase") - public String uppercase( - @KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) { - return text.toUpperCase(Locale.ROOT); - } - - @DefineKernelFunction(description = "Remove spaces to the left of a string.", name = "LStrip") - public String lStrip( - @KernelFunctionParameter(description = "Text to edit", name = "input") String text) { - return text.replaceAll("^ +", ""); - } - - @DefineKernelFunction(description = "Remove spaces to the right of a string.", name = "RStrip") - public String rStrip( - @KernelFunctionParameter(description = "Text to edit", name = "input") String text) { - return text.replaceAll(" +$", ""); - } - - @DefineKernelFunction(description = "Remove spaces to the left and right of a string", name = "Strip") - public String strip( - @KernelFunctionParameter(description = "Text to edit", name = "input") String input) { - return input.trim(); - } - - @DefineKernelFunction(description = "Change all string chars to lowercase", name = "lowercase") - public String lowercase( - @KernelFunctionParameter(description = "Text to lowercase", name = "input") String input) { - return input.toLowerCase(Locale.ROOT); - } - - ///

- /// Concatenate two strings into one - /// - /// First input to concatenate with - /// Second input to concatenate with - /// Concatenation result from both inputs. - @DefineKernelFunction(description = "Concat two strings into one.", name = "Concat") - public String concat( - @KernelFunctionParameter(description = "First input to concatenate with", name = "input") String input, - @KernelFunctionParameter(description = "Second input to concatenate with", name = "input2") String input2) { - return (input + input2); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/SearchUrlPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/SearchUrlPlugin.java deleted file mode 100644 index a30add3f5..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/SearchUrlPlugin.java +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.web; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -public class SearchUrlPlugin { - /* - * Amazon Search URLs - */ - /// - /// Get search URL for Amazon - /// - @DefineKernelFunction(name = "AmazonSearchUrl", description = "Return URL for Amazon search query") - public String AmazonSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.amazon.com/s?k=%s", encoded); - } - - /* - * Bing Search URLs - */ - /// - /// Get search URL for Bing - /// - @DefineKernelFunction(name = "BingSearchUrl", description = "Return URL for Bing search query.") - public String BingSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/search?q=%s", encoded); - } - - /// - /// Get search URL for Bing Images - /// - @DefineKernelFunction(name = "BingImagesSearchUrl", description = "Return URL for Bing Images search query.") - public String BingImagesSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/images/search?q=%s", encoded); - } - - /// - /// Get search URL for Bing Maps - /// - @DefineKernelFunction(name = "BingMapsSearchUrl", description = "Return URL for Bing Maps search query.") - public String BingMapsSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/maps?q=%s", encoded); - } - - /// - /// Get search URL for Bing Shopping - /// - @DefineKernelFunction(name = "BingShoppingSearchUrl", description = "Return URL for Bing Shopping search query.") - public String BingShoppingSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/shop?q=%s", encoded); - } - - /// - /// Get search URL for Bing News - /// - @DefineKernelFunction(name = "BingNewsSearchUrl", description = "Return URL for Bing News search query.") - public String BingNewsSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/news/search?q=%s", encoded); - } - - /// - /// Get search URL for Bing Travel - /// - @DefineKernelFunction(name = "BingTravelSearchUrl", description = "Return URL for Bing Travel search query.") - public String BingTravelSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.bing.com/travel/search?q=%s", encoded); - } - - /* - * Facebook Search URLs - */ - /// - /// Get search URL for Facebook - /// - @DefineKernelFunction(name = "FacebookSearchUrl", description = "Return URL for Facebook search query.") - public String FacebookSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.facebook.com/search/top/?q=%s", encoded); - } - - /* - * GitHub Search URLs - */ - /// - /// Get search URL for GitHub - /// - @DefineKernelFunction(name = "GitHubSearchUrl", description = "Return URL for GitHub search query.") - public String GitHubSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://github.com/search?q=%s", encoded); - } - - /* - * LinkedIn Search URLs - */ - /// - /// Get search URL for LinkedIn - /// - @DefineKernelFunction(name = "LinkedInSearchUrl", description = "Return URL for LinkedIn search query.") - public String LinkedInSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://www.linkedin.com/search/results/index/?keywords=%s", encoded); - } - - /* - * Twitter Search URLs - */ - /// - /// Get search URL for Twitter - /// - @DefineKernelFunction(name = "TwitterSearchUrl", description = "Return URL for Twitter search query.") - public String TwitterSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://twitter.com/search?q=%s", encoded); - } - - /* - * Wikipedia Search URLs - */ - /// - /// Get search URL for Wikipedia - /// - @DefineKernelFunction(name = "WikipediaSearchUrl", description = "Return URL for Wikipedia search query.") - public String WikipediaSearchUrl( - @KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) { - String encoded = encode(query); - return String.format("https://wikipedia.org/w/index.php?search=%s", encoded); - } - - private static String encode(String query) { - try { - return URLEncoder.encode(query, "UTF-8"); - } catch (UnsupportedEncodingException e) { - // should never happen since UTF-8 is always supported - return query; - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/WebSearchEnginePlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/WebSearchEnginePlugin.java deleted file mode 100644 index 060c7b343..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/plugins/web/WebSearchEnginePlugin.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.web; - -import com.microsoft.semantickernel.connectors.WebSearchEngineConnector; -import com.microsoft.semantickernel.connectors.WebSearchEngineConnector.WebPage; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.util.stream.Collectors; -import reactor.core.publisher.Mono; - -/// -/// Web search engine plugin (e.g. Bing). -/// -public class WebSearchEnginePlugin { - - /// - /// The count parameter name. - /// - public static final String COUNT_PARAM = "count"; - - /// - /// The offset parameter name. - /// - public static final String OFFSET_PARAM = "offset"; - - private final WebSearchEngineConnector connector; - - /// - /// Initializes a new instance of the class. - /// - /// The web search engine connector. - public WebSearchEnginePlugin(WebSearchEngineConnector connector) { - this.connector = connector; - } - - /// - /// Performs a web search using the provided query, count, and offset. - /// - /// The text to search for. - /// The number of results to return. Default is 1. - /// The number of results to skip. Default is 0. - /// A cancellation token to observe while waiting for the task to complete. - /// A task that represents the asynchronous operation. The value of the TResult parameter contains the search results as a string. - /// - /// This method is marked as "unsafe." The usage of JavaScriptEncoder.UnsafeRelaxedJsonEscaping may introduce security risks. - /// Only use this method if you are aware of the potential risks and have validated the input to prevent security vulnerabilities. - /// - @DefineKernelFunction(name = "search", description = "Searches the web for the given query", returnType = "java.lang.String") - public Mono searchAsync( - @KernelFunctionParameter(description = "The search query", name = "query", type = String.class) String query, - @KernelFunctionParameter(description = "The number of results to return", name = "count", defaultValue = "1", type = int.class) int count, - @KernelFunctionParameter(description = "The number of results to skip", name = "offset", defaultValue = "0", type = int.class) int offset) { - - return connector.searchAsync(query, count, offset).map(results -> { - - if (results == null || results.isEmpty()) { - throw new SKException("Failed to get a response from the web search engine."); - } - - return count == 1 - ? results.get(0).getSnippet() - // TODO: .NET code does `JsonSerializer.Serialize(results, s_jsonOptionsCache)` here - // The joiner results in "[\"result1\",\"result2\"]" - : results.stream() - .limit(count) - .map(WebPage::getSnippet) - .collect(Collectors.joining("\",\"", "[\"", "\"]")); - }); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example11_WebSearchQueries.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example11_WebSearchQueries.java deleted file mode 100644 index 1386cc619..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example11_WebSearchQueries.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.web.SearchUrlPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; - -public class Example11_WebSearchQueries { - - public static void main(String[] args) { - - var kernel = Kernel.builder().build(); - - // Load native plugins - var searchUrlPlugin = KernelPluginFactory.createFromObject(new SearchUrlPlugin(), - "SearchUrlPlugin"); - var bingSearchFunction = searchUrlPlugin.get("BingSearchUrl"); - - // Run - var ask = "What's the largest building in Europe?"; - var kernelArguments = KernelArguments.builder() - .withVariable("query", ask) - .build(); - - var result = kernel.invokeAsync(bingSearchFunction).withArguments(kernelArguments).block(); - - System.out.println(ask); - System.out.println(result.getResult()); - - /* - * Expected output: - * ======== WebSearchQueries ======== - * What's the tallest building in Europe? - * - * https://www.bing.com/search?q=What%27s%20the%20tallest%20building%20in%20Europe%3F - * == DONE == - */ - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example20_HuggingFace.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example20_HuggingFace.java deleted file mode 100644 index 14fccf0a0..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example20_HuggingFace.java +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.core.credential.AzureKeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.huggingface.HuggingFaceClient; -import com.microsoft.semantickernel.aiservices.huggingface.services.HuggingFaceTextGenerationService; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; - -public class Example20_HuggingFace { - - private static final String HUGGINGFACE_CLIENT_KEY = System.getenv("HUGGINGFACE_CLIENT_KEY"); - private static final String HUGGINGFACE_CLIENT_ENDPOINT = System.getenv( - "HUGGINGFACE_CLIENT_ENDPOINT"); - - public static void main(String[] args) { - //runConversationApiExampleAsync(); - runInferenceApiExampleAsync(); - } - - public static void runInferenceApiExampleAsync() { - System.out.println("\n======== HuggingFace Inference API example ========\n"); - - HuggingFaceClient client = HuggingFaceClient.builder() - .credential(new AzureKeyCredential(HUGGINGFACE_CLIENT_KEY)) - .endpoint(HUGGINGFACE_CLIENT_ENDPOINT) - .build(); - - var chatCompletion = HuggingFaceTextGenerationService.builder() - .withModelId("gpt2-24") - .withHuggingFaceClient(client) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(TextGenerationService.class, chatCompletion) - .build(); - - var questionAnswerFunction = KernelFunctionFromPrompt.builder() - .withTemplate("Question: {{$input}}; Answer:") - .build(); - - var result = kernel.invokeAsync(questionAnswerFunction) - .withArguments( - KernelArguments.builder() - .withVariable("input", "What is New York?") - .build()) - .withResultType(String.class) - .block(); - - System.out.println(result.getResult()); - } - - /* - * - * public static void runConversationApiExampleAsync() { - * System.out.println("\n======== HuggingFace Inference API example ========\n"); - * - * HuggingFaceClient client = HuggingFaceClient.builder() - * .credential(new AzureKeyCredential(HUGGINGFACE_CLIENT_KEY)) - * .endpoint(HUGGINGFACE_CLIENT_ENDPOINT) - * .build(); - * - * var chatCompletion = HuggingFaceChatCompletionService.builder() - * .withModelId("msft-dialogpt-medium-13") - * .withHuggingFaceClient(client) - * .build(); - * - * Kernel kernel = Kernel.builder() - * .withAIService(ChatCompletionService.class, chatCompletion) - * .build(); - * - * var questionAnswerFunction = KernelFunctionFromPrompt.builder() - * .withTemplate(""" - * Assistant is a large language model that answers questions. - * What is your question? - * {{$input}} - * """) - * .build(); - * - * var result = kernel.invokeAsync(questionAnswerFunction) - * .withArguments( - * KernelFunctionArguments.builder() - * .withVariable("input", "What is New York?") - * .build() - * ) - * .withResultType(String.class) - * .block(); - * - * System.out.println(result.getResult()); - * } - * - */ -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example42_KernelBuilder.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example42_KernelBuilder.java deleted file mode 100644 index b95da4311..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example42_KernelBuilder.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.azure.core.http.HttpClient; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; - -public class Example42_KernelBuilder { - - public static void main(String[] args) { - - ///////////////////////////////////////////////////////// - // KernelBuilder provides a simple way to configure a Kernel. This constructs a kernel - // with logging and an Azure OpenAI chat completion service configured. - OpenAIAsyncClient client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential("a-key")) - .endpoint("an-endpoint") - .buildAsyncClient(); - - Kernel kernel1 = Kernel.builder() - .withAIService(ChatCompletionService.class, - OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build()) - .build(); - ///////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////// - // Kernel with custom HttpClient - HttpClient httpClient = HttpClient.createDefault(); - - OpenAIAsyncClient client2 = new OpenAIClientBuilder() - .httpClient(httpClient) - .credential(new KeyCredential("a-key")) - .buildAsyncClient(); - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId("gpt-35-turbo") - .withOpenAIAsyncClient(client2) - .build(); - - Kernel kernel2 = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - ///////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////// - //Plugins may also be configured via the corresponding Plugins property - - Kernel kernel3 = Kernel.builder() - .withPlugin(KernelPluginFactory.createFromObject(new ConversationSummaryPlugin(), - "ConversationSummaryPlugin")) - .build(); - - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example43_GetModelResult.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example43_GetModelResult.java deleted file mode 100644 index 7b1e5752e..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example43_GetModelResult.java +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.ai.openai.models.CompletionsUsage; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example43_GetModelResult { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Open AI - ChatGPT Streaming ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - - System.out.println("======== Inline Function Definition + Invocation ========"); - - // Create function - String FunctionDefinition = "Hi, give me 5 book suggestions about: {{$input}}"; - KernelFunction myFunction = KernelFunctionFromPrompt.builder() - .withTemplate(FunctionDefinition).build(); - - // Invoke function through kernel - FunctionResult result = kernel.invokeAsync( - myFunction) - .withArguments( - KernelArguments.builder() - .withVariable("input", "travel") - .build()) - .block(); - - // Display results - System.out.println(result.getResult()); - System.out.println( - "Usage: " + ((CompletionsUsage) result - .getMetadata() - .getUsage()).getTotalTokens()); - System.out.println(); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example49_LogitBias.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example49_LogitBias.java deleted file mode 100644 index e3a8ce22d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example49_LogitBias.java +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -/** - * Logit_bias is an optional parameter that modifies the likelihood of specified tokens appearing in - * a Completion. When using the Token Selection Biases parameter, the bias is added to the logits - * generated by the model prior to sampling. - */ -public class Example49_LogitBias { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - public static void main(String[] args) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - // To use Logit Bias you will need to know the token ids of the words you want to use. - // Getting the token ids using the GPT Tokenizer: https://platform.openai.com/tokenizer - - // The following text is the tokenized version of the book related tokens - // "novel literature reading author library story chapter paperback hardcover ebook publishing fiction nonfiction manuscript textbook bestseller bookstore reading list bookworm" - var keys = new int[] { 39142, 301, 17649, 5403, 3229, 6875, 3446, 12735, 86831, 2653, 3773, - 35097, 23763, 17422, 2536, 58162, 47913, 56185, 1888, 35199, 79761, 5403, 1160, - 2363, - 56741 }; - /* - * // If using GPT-3 (not GPT-3.5 or GPT-4) - * var keys = new int[]{3919, 626, 9285, 3555, 1772, 5888, 1621, 6843, 46771, 1327, 9631, - * 47179, 12407, 10165, 1729, 24046, 17116, 28979, 1266, 32932, 44346, 3555, 1351, 1492, - * 25323}; - */ - // This will make the model try its best to avoid any of the above related words. - //-100 to potentially ban all the tokens from the list. - Map biases = new HashMap<>(); - Arrays.stream(keys) - .asLongStream() - .forEach(key -> biases.put((int) key, -100)); - - var settings = PromptExecutionSettings.builder() - .withTokenSelectionBiases(biases) - .build(); - - var invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - var chatHistory = new ChatHistory("You are a librarian expert"); - - // First user message - chatHistory.addUserMessage("Hi, I'm looking some suggestions"); - messageOutputAsync(chatHistory); - - var replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory, - kernel, invocationContext).block(); - - chatHistory = new ChatHistory(replyMessage); - - messageOutputAsync(chatHistory); - - chatHistory.addUserMessage( - "I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); - messageOutputAsync(chatHistory); - - replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory, - kernel, invocationContext).block(); - chatHistory = new ChatHistory(replyMessage); - messageOutputAsync(chatHistory); - - } - - private static void messageOutputAsync(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage(); - - System.out.println(message.get().getAuthorRole() + ": " + message.get().getContent()); - System.out.println("------------------------"); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java deleted file mode 100644 index 8b171d7e0..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.microsoft.semantickernel.text.TextChunker; -import java.util.List; - -public class Example55_TextChunker { - - private static final String text = """ - The city of Venice, located in the northeastern part of Italy, - is renowned for its unique geographical features. Built on more than 100 small islands in a lagoon in the - Adriatic Sea, it has no roads, just canals including the Grand Canal thoroughfare lined with Renaissance and - Gothic palaces. The central square, Piazza San Marco, contains St. Mark's Basilica, which is tiled with Byzantine - mosaics, and the Campanile bell tower offering views of the city's red roofs. - - The Amazon Rainforest, also known as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that - covers most of the Amazon basin of South America. This basin encompasses 7 million square kilometers, of which - 5.5 million square kilometers are covered by the rainforest. This region includes territory belonging to nine nations - and 3.4 million square kilometers of uncontacted tribes. The Amazon represents over half of the planet's remaining - rainforests and comprises the largest and most biodiverse tract of tropical rainforest in the world. - - The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands - stretching for over 2,300 kilometers over an area of approximately 344,400 square kilometers. The reef is located in the - Coral Sea, off the coast of Queensland, Australia. The Great Barrier Reef can be seen from outer space and is the world's - biggest single structure made by living organisms. This reef structure is composed of and built by billions of tiny organisms, - known as coral polyps. - """ - .stripIndent(); - - public static void main(String[] args) { - RunExample(); - - // TODO: This example should also demo using token counters, not supported in Java atm - } - - private static void RunExample() { - System.out.println("=== Text chunking ==="); - - var lines = TextChunker.splitPlainTextLines(text, 40); - var paragraphs = TextChunker.splitPlainTextParagraphs(lines, 120); - - writeParagraphsToConsole(paragraphs); - } - - private static void writeParagraphsToConsole(List paragraphs) { - for (var i = 0; i < paragraphs.size(); i++) { - System.out.println(paragraphs.get(i)); - - if (i < paragraphs.size() - 1) { - System.out.println("------------------------"); - } - } - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example57_KernelHooks.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example57_KernelHooks.java deleted file mode 100644 index ffa09a677..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example57_KernelHooks.java +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.ChatRequestMessage; -import com.azure.ai.openai.models.ChatRequestSystemMessage; -import com.azure.ai.openai.models.CompletionsUsage; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.Kernel.Builder; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.hooks.FunctionInvokedEvent; -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook; -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook; -import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook; -import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook; -import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.hooks.PreChatCompletionEvent; -import com.microsoft.semantickernel.hooks.PromptRenderedEvent; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.OutputVariable; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -public class Example57_KernelHooks { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - Builder kernelBuilder = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion); - - getUsageAsync(kernelBuilder.build()); - getRenderedPromptAsync(kernelBuilder.build()); - changingResultAsync(kernelBuilder.build()); - beforeInvokeCancellationAsync(kernelBuilder.build()); - afterInvokeCancellationAsync(kernelBuilder.build()); - chatCompletionHook(kernelBuilder.build()); - invocationHook(kernelBuilder.build()); - } - - /// - /// Demonstrate using kernel invocation-hooks to monitor usage: - /// - /// - /// - private static void getUsageAsync(Kernel kernel) { - System.out.println("\n======== Get Usage Data ========\n"); - - // Initialize prompt - String functionPrompt = "Write a random paragraph about: {{$input}}."; - - var excuseFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Excuse") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(100) - .withTemperature(0.4) - .withTopP(1) - .build()) - .withOutputVariable(new OutputVariable<>("result", String.class)) - .build(); - - FunctionInvokingHook preHook = event -> { - System.out.println( - event.getFunction().getName() + " : Pre Execution Handler - Triggered"); - return event; - }; - - FunctionInvokingHook removedPreExecutionHandler = event -> { - System.out.println( - event.getFunction().getName() + " : Pre Execution Handler - Should not trigger"); - return event; - }; - - FunctionInvokedHook postExecutionHandler = event -> { - System.out.println( - event.getFunction().getName() + " : Post Execution Handler - Usage: " - + ((CompletionsUsage) event - .getResult() - .getMetadata() - .getUsage()) - .getTotalTokens()); - return event; - }; - - kernel.getGlobalKernelHooks().addHook(preHook); - - // Demonstrate pattern for removing a handler. - kernel.getGlobalKernelHooks().addHook("pre-invoke-removed", removedPreExecutionHandler); - kernel.getGlobalKernelHooks().removeHook("pre-invoke-removed"); - - kernel.getGlobalKernelHooks().addHook(postExecutionHandler); - - // Invoke prompt to trigger execution hooks. - String input = "I missed the F1 final race"; - var result = kernel.invokeAsync(excuseFunction) - .withArguments( - KernelArguments - .builder() - .withVariable("input", input) - .build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } - - /// - /// Demonstrate using kernel-hooks to around prompt rendering: - /// - /// - /// - private static void getRenderedPromptAsync(Kernel kernel) { - System.out.println("\n======== Get Rendered Prompt ========\n"); - - // Initialize prompt - String functionPrompt = "Write a random paragraph about: {{$input}} in the style of {{$style}}."; - - var excuseFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Excuse") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(100) - .withTemperature(0.4) - .withTopP(1) - .build()) - .build(); - - PromptRenderingHook myRenderingHandler = event -> { - System.out.println( - event.getFunction().getName() + " : Prompt Rendering Handler - Triggered"); - - event.getArguments().put("style", ContextVariable.of("Seinfeld")); - return event; - }; - - PromptRenderedHook myRenderedHandler = event -> { - System.out.println( - event.getFunction().getName() + " : Prompt Rendered Handler - Triggered"); - - String prompt = event.getPrompt() + "\nUSE SHORT, CLEAR, COMPLETE SENTENCES."; - - return new PromptRenderedEvent( - event.getFunction(), - event.getArguments(), - prompt); - }; - kernel.getGlobalKernelHooks().addHook(myRenderingHandler); - kernel.getGlobalKernelHooks().addHook(myRenderedHandler); - - // Invoke prompt to trigger execution hooks. - String input = "I missed the F1 final race"; - var result = kernel.invokeAsync(excuseFunction) - .withArguments( - KernelArguments - .builder() - .withVariable("input", input) - .build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } - - /// - /// Demonstrate using kernel invocation-hooks to post process result: - /// - /// - private static void changingResultAsync(Kernel kernel) { - System.out.println("\n======== Changing/Filtering Function Result ========\n"); - - // Initialize function - String functionPrompt = "Write a paragraph about Handlers."; - - var writerFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Writer") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(100) - .withTemperature(0.4) - .withTopP(1) - .build()) - .build(); - - FunctionInvokedHook hook = event -> { - String result = (String) event.getResult().getResult(); - result = result.replaceAll("[aeiouAEIOU0-9]", "*"); - - return new FunctionInvokedEvent( - event.getFunction(), - event.getArguments(), - new FunctionResult<>( - ContextVariable.of(result), - event.getResult().getMetadata(), - result)); - }; - kernel.getGlobalKernelHooks().addHook(hook); - - // Invoke prompt to trigger execution hooks. - var result = kernel.invokeAsync(writerFunction) - .withArguments( - KernelArguments.builder().build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } - - /// - /// Demonstrate using kernel invocation-hooks to cancel prior to execution: - /// - /// - /// - private static void beforeInvokeCancellationAsync(Kernel kernel) { - System.out.println("\n======== Cancelling Pipeline Execution - Invoking event ========\n"); - - // Initialize prompt - String functionPrompt = "Write a paragraph about: Cancellation."; - - var writerFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Writer") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(1000) - .withTemperature(1) - .withTopP(0.5) - .build()) - .build(); - - FunctionInvokingHook hook = event -> { - System.out.println( - event.getFunction().getName() - + " : FunctionInvoking - Cancelling before execution"); - throw new RuntimeException("Cancelled"); - }; - - kernel.getGlobalKernelHooks().addHook(hook); - - try { - // Invoke prompt to trigger execution hooks. - var result = kernel.invokeAsync(writerFunction) - .withArguments( - KernelArguments.builder().build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); - } - } - - /// - /// Demonstrate using kernel invocation-hooks to cancel post after execution: - /// - /// - /// - private static void afterInvokeCancellationAsync(Kernel kernel) { - System.out.println("\n======== Cancelling Pipeline Execution - Invoked event ========\n"); - - // Initialize prompts - var firstFunction = KernelFunctionFromPrompt.builder() - .withTemplate("Write a phrase with Invoke.").build(); - var secondFunction = KernelFunctionFromPrompt.builder() - .withTemplate("Write a phrase with Cancellation.").build(); - - AtomicInteger invokingCounter = new AtomicInteger(0); - kernel.getGlobalKernelHooks().addHook((FunctionInvokingHook) event -> { - invokingCounter.incrementAndGet(); - return event; - }); - - AtomicInteger invokedCounter = new AtomicInteger(0); - kernel.getGlobalKernelHooks().addHook((FunctionInvokedHook) event -> { - invokedCounter.incrementAndGet(); - throw new RuntimeException("Cancelled"); - }); - - // Invoke prompt to trigger execution hooks. - try { - var result = kernel.invokeAsync(secondFunction) - .withArguments(KernelArguments.builder().build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); - System.out.println("Function Invoked Times: " + invokedCounter.get()); - System.out.println("Function Invoking Times: " + invokedCounter.get()); - } - } - - private static void chatCompletionHook(Kernel kernel) { - // Initialize prompt - String functionPrompt = "Write a paragraph about hats"; - - var writerFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Writer") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(1000) - .withTemperature(1) - .withTopP(0.5) - .build()) - .build(); - - kernel.getGlobalKernelHooks().addPreChatCompletionHook(event -> { - ChatCompletionsOptions options = event.getOptions(); - List messages = options.getMessages(); - - messages = new ArrayList<>(messages); - messages.add( - new ChatRequestSystemMessage("Use upper case text when responding to the prompt.")); - - return new PreChatCompletionEvent( - PreChatCompletionHook.cloneOptionsWithMessages(options, messages)); - }); - - kernel.getGlobalKernelHooks().addPostChatCompletionHook(event -> { - System.out.println("Chat completion"); - System.out.println("Id: " + event.getChatCompletions().getId()); - return event; - }); - - try { - // Invoke prompt to trigger execution hooks. - var result = kernel.invokeAsync(writerFunction) - .withArguments( - KernelArguments.builder().build()) - .block(); - System.out.println("Function Result: " + result.getResult()); - } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); - } - } - - /** - * Show use of hooks added on a single invocations. - * - * @param kernel - */ - private static void invocationHook(Kernel kernel) { - // Initialize prompt - String functionPrompt = "Write a paragraph about hats"; - - var writerFunction = KernelFunctionFromPrompt.builder() - .withTemplate(functionPrompt) - .withName("Writer") - .withDefaultExecutionSettings(PromptExecutionSettings - .builder() - .withMaxTokens(1000) - .withTemperature(1) - .withTopP(0.5) - .build()) - .build(); - - KernelHooks kernelHooks = new KernelHooks(); - kernelHooks.addPreChatCompletionHook(event -> { - ChatCompletionsOptions options = event.getOptions(); - List messages = options.getMessages(); - - messages = new ArrayList<>(messages); - messages.add( - new ChatRequestSystemMessage("Use upper case text when responding to the prompt.")); - - return new PreChatCompletionEvent( - PreChatCompletionHook.cloneOptionsWithMessages(options, messages)); - }); - - try { - // Invoke prompt to trigger execution hooks. - var result = kernel.invokeAsync(writerFunction) - .withArguments(KernelArguments.builder().build()) - .addKernelHooks(kernelHooks) - .block(); - System.out.println("Function Result: " + result.getResult()); - } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example61_MultipleLLMs.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example61_MultipleLLMs.java deleted file mode 100644 index 0396d575f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example61_MultipleLLMs.java +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.Arrays; -import java.util.HashMap; - -public class Example61_MultipleLLMs { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - public static void main(String[] args) { - System.out.println("======== Example61_MultipleLLMs ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - System.out.println("======== Using Chat GPT model for text generation ========"); - - var openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withServiceId("AzureOpenAIChat") - .withModelId("gpt-35-turbo-2") - .build(); - - var textGenerationService = TextGenerationService.builder() - .withOpenAIAsyncClient(client) - .withServiceId("AzureOpenAIText") - .withModelId("text-davinci-003") - .build(); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .withAIService(TextGenerationService.class, textGenerationService) - .build(); - - runByServiceIdAsync(kernel, "AzureOpenAIText"); - runByServiceIdAsync(kernel, "AzureOpenAIChat"); - - runByModelIdAsync(kernel, "gpt-35-turbo-2"); - - runByFirstModelIdAsync(kernel, "text-davinci-003", "gpt-35-turbo-2"); - } - - public static void runByServiceIdAsync(Kernel kernel, String serviceId) { - System.out.println("======== Service Id: " + serviceId + " ========"); - - var prompt = "Hello AI, what can you do for me?"; - - KernelArguments arguments = KernelArguments.builder().build(); - - KernelFunction func = KernelFunctionFromPrompt - .builder() - .withTemplate(prompt) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withServiceId(serviceId) - .build()) - .withOutputVariable("result", "java.lang.String") - .build(); - - var result = kernel.invokeAsync(func).withArguments(arguments).block(); - System.out.println(result.getResult()); - } - - public static void runByModelIdAsync(Kernel kernel, String modelId) { - System.out.println("======== Model Id: " + modelId + " ========"); - - var prompt = "Hello AI, what can you do for me?"; - - var result = kernel.invokeAsync( - KernelFunctionFromPrompt - .builder() - .withTemplate(prompt) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withModelId(modelId) - .build()) - .withOutputVariable("result", "java.lang.String") - .build()) - .withArguments(KernelArguments.builder().build()) - .block(); - - System.out.println(result.getResult()); - } - - public static void runByFirstModelIdAsync(Kernel kernel, String... modelIds) { - System.out.println("======== Model Ids: " + String.join(",", modelIds) + " ========"); - - var prompt = "Hello AI, what can you do for me?"; - - var modelSettings = new HashMap(); - - Arrays.stream(modelIds).forEach( - modelId -> { - modelSettings.put( - modelId, - PromptExecutionSettings.builder() - .withModelId(modelId) - .build()); - }); - - var promptConfig = PromptTemplateConfig.defaultTemplateBuilder() - .withTemplate(prompt) - .withName("HelloAI") - .withExecutionSettings(modelSettings) - .build(); - - var function = KernelFunctionFromPrompt.builder().withPromptTemplateConfig(promptConfig) - .build(); - - var result = kernel.invokeAsync(function) - .withArguments(KernelArguments.builder().build()) - .block(); - - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java deleted file mode 100644 index 5e01d13a2..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.services.AIServiceCollection; -import com.microsoft.semantickernel.services.AIServiceSelection; -import com.microsoft.semantickernel.services.BaseAIServiceSelector; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.Map; -import javax.annotation.Nullable; - -public class Example62_CustomAIServiceSelector { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - public static void main(String[] args) { - System.out.println("======== Example62_CustomAIServiceSelector ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // Build a kernel with multiple chat completion services - - var openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withServiceId("AzureOpenAIChat") - .withModelId("gpt-35-turbo-2") - .build(); - - var textGenerationService = TextGenerationService.builder() - .withOpenAIAsyncClient(client) - .withServiceId("AzureOpenAIText") - .withModelId("text-davinci-003") - .build(); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .withAIService(TextGenerationService.class, textGenerationService) - .withServiceSelector(CustomAIServiceSelector::new) - .build(); - - var prompt = "Hello AI, what can you do for me?"; - - KernelArguments arguments = KernelArguments.builder().build(); - - KernelFunction func = KernelFunctionFromPrompt - .builder() - .withTemplate(prompt) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withTopP(1.0) - .build()) - .withOutputVariable("result", "java.lang.String") - .build(); - - var result = kernel.invokeAsync(func).withArguments(arguments).block(); - System.out.println(result.getResult()); - } - - // A dumb AIServiceSelector that just returns the first service and execution settings it finds - static class CustomAIServiceSelector extends BaseAIServiceSelector { - - public CustomAIServiceSelector(AIServiceCollection services) { - super(services); - } - - @Nullable - @Override - @SuppressWarnings("unchecked") - public AIServiceSelection trySelectAIService( - Class serviceType, - - @Nullable KernelFunction function, - - @Nullable KernelArguments arguments, - Map, AIService> services) { - - // Just get the first one - PromptExecutionSettings executionSettings = function.getExecutionSettings() - .values().stream().findFirst().get(); - // unchecked cast - T service = (T) services.values().stream().findFirst().get(); - - return new AIServiceSelection<>( - service, - executionSettings); - } - - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example67_KernelStreaming.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example67_KernelStreaming.java deleted file mode 100644 index f6f686810..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example67_KernelStreaming.java +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.StreamingChatContent; -import java.util.concurrent.CountDownLatch; - -public class Example67_KernelStreaming { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws InterruptedException { - System.out.println("======== Open AI - ChatGPT Streaming ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatGPT = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - ChatHistory chatHistory = new ChatHistory("You are a librarian, expert about books"); - - // First user message - chatHistory.addUserMessage("Hi, I'm looking for book suggestions"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - - chatHistory.addUserMessage( - "I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - } - - private static void messageOutput(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage().get(); - System.out.println(message.getAuthorRole() + ": " + message.getContent()); - System.out.println("------------------------"); - } - - private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory) - throws InterruptedException { - var reply = chatGPT.getStreamingChatMessageContentsAsync(chatHistory, null, null); - System.out.print(AuthorRole.ASSISTANT + ": "); - - CountDownLatch cdl = new CountDownLatch(1); - reply - .groupBy(StreamingChatContent::getId) - .doOnComplete(() -> { - cdl.countDown(); - }) - .subscribe(group -> { - group - .filter(msg -> msg.getContent() != null) - .subscribe( - msg -> { - System.out.print(msg.getContent()); - }); - }); - - cdl.await(); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java deleted file mode 100644 index 23bd37787..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; - -public class Example69_MutableKernelPlugin { - - /** - * Mutable KernelPlugin example - *

- * KernelFunction can be added directly to the function collection of the KernelPlugin by using - * KernelPlugin.getFunctions and putting the corresponding KernelFunction - */ - public static void main(String[] args) throws NoSuchMethodException { - System.out.println("======== Example69_MutableKernelPlugin ========"); - - KernelPlugin plugin = new KernelPlugin("Plugin", "Mutable plugin", null); - plugin.addFunction(KernelFunction.createFromMethod( - Time.class.getMethod("date"), new Time()) - .withFunctionName("dateFunction") - .build()); - - Kernel kernel = Kernel.builder() - .withPlugin(plugin) - .build(); - - var result = kernel.invokeAsync(kernel.getFunction("Plugin", "dateFunction")) - .block(); - - System.out.println("Result: " + result.getResult()); - } - - public static class Time { - - @DefineKernelFunction(name = "date") - public String date() { - return "2021-09-01"; - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/RunAll.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/RunAll.java deleted file mode 100644 index 44a979796..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/RunAll.java +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples; - -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example17_ChatGPT; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example30_ChatWithPrompts; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example33_Chat; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example44_MultiChatCompletion; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example63_ChatCompletionPrompts; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Example_ChatWithResponseFormat; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Example_ChatWithResponseFormatToolCall; -import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example08_RetryHandler; -import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example41_HttpClientUsage; -import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example58_ConfigureExecutionSettings; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example01_NativeFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example05_InlineFunctionDefinition; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example09_FunctionTypes; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example27_PromptFunctionsUsingChatGPT; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example59_OpenAIFunctionCalling; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.java.KernelFunctionYaml_Example; -import com.microsoft.semantickernel.samples.syntaxexamples.memory.VectorStoreWithAzureAISearch; -import com.microsoft.semantickernel.samples.syntaxexamples.plugin.Example10_DescribeAllPluginsAndFunctions; -import com.microsoft.semantickernel.samples.syntaxexamples.plugin.Example13_ConversationSummaryPlugin; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example06_TemplateLanguage; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example56_TemplateMethodFunctionsWithMultipleArguments; -import com.microsoft.semantickernel.samples.syntaxexamples.template.Example64_MultiplePromptTemplates; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; - -/** - * Run all the syntax examples. - *

- * Refer to the - * README for configuring your environment to run the examples. - */ -public class RunAll { - - public static void main(String[] args) { - List mains = Arrays.asList( - VectorStoreWithAzureAISearch::main, - Example01_NativeFunctions::main, - Example03_Arguments::main, - Example05_InlineFunctionDefinition::main, - Example06_TemplateLanguage::main, - Example08_RetryHandler::main, - Example09_FunctionTypes::main, - Example10_DescribeAllPluginsAndFunctions::main, - Example13_ConversationSummaryPlugin::main, - Example17_ChatGPT::main, - Example27_PromptFunctionsUsingChatGPT::main, - Example30_ChatWithPrompts::main, - Example33_Chat::main, - Example41_HttpClientUsage::main, - Example42_KernelBuilder::main, - Example43_GetModelResult::main, - Example44_MultiChatCompletion::main, - Example49_LogitBias::main, - Example55_TextChunker::main, - Example56_TemplateMethodFunctionsWithMultipleArguments::main, - Example57_KernelHooks::main, - Example58_ConfigureExecutionSettings::main, - Example59_OpenAIFunctionCalling::main, - Example60_AdvancedMethodFunctions::main, - Example62_CustomAIServiceSelector::main, - Example63_ChatCompletionPrompts::main, - Example64_MultiplePromptTemplates::main, - Example69_MutableKernelPlugin::main, - KernelFunctionYaml_Example::main, - Example_ChatWithResponseFormat::main, - Example_ChatWithResponseFormatToolCall::main); - - Scanner scanner = new Scanner(System.in); - mains.forEach(mainMethod -> { - try { - - System.out.println("========================================"); - mainMethod.run(args); - - System.out.println("Press any key to continue..."); - scanner.nextLine(); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } - - public interface MainMethod { - - void run(String[] args) throws Exception; - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java deleted file mode 100644 index 336406a33..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/agents/CompletionAgent.java +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.agents; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.agents.AgentInvokeOptions; -import com.microsoft.semantickernel.agents.AgentThread; -import com.microsoft.semantickernel.agents.chatcompletion.ChatCompletionAgent; -import com.microsoft.semantickernel.agents.chatcompletion.ChatHistoryAgentThread; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.DefaultPromptTemplate; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.github.GitHubModel; -import com.microsoft.semantickernel.samples.plugins.github.GitHubPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; - -import java.util.List; -import java.util.Scanner; - -public class CompletionAgent { - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - private static final String GITHUB_PAT = System.getenv("GITHUB_PAT"); - - public static void main(String[] args) { - System.out.println("======== ChatCompletion Agent ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - System.out.println("------------------------"); - - ChatCompletionService chatCompletion = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletion) - .withPlugin(KernelPluginFactory.createFromObject(new GitHubPlugin(GITHUB_PAT), - "GitHubPlugin")) - .build(); - - InvocationContext invocationContext = InvocationContext.builder() - .withFunctionChoiceBehavior(FunctionChoiceBehavior.auto(true)) - .withContextVariableConverter(new ContextVariableTypeConverter<>( - GitHubModel.Issue.class, - o -> (GitHubModel.Issue) o, - o -> o.toString(), - s -> null)) - .build(); - - ChatCompletionAgent agent = ChatCompletionAgent.builder() - .withKernel(kernel) - .withKernelArguments( - KernelArguments.builder() - .withVariable("repository", "microsoft/semantic-kernel-java") - .withExecutionSettings(PromptExecutionSettings.builder() - .build()) - .build()) - .withInvocationContext(invocationContext) - .withTemplate( - DefaultPromptTemplate.build( - PromptTemplateConfig.builder() - .withTemplate( - """ - You are an agent designed to query and retrieve information from a single GitHub repository in a read-only manner. - You are also able to access the profile of the active user. - - Use the current date and time to provide up-to-date details or time-sensitive responses. - - The repository you are querying is a public repository with the following name: {{$repository}} - - The current date and time is: {{$now}}. - """) - .build())) - .build(); - - AgentThread agentThread = new ChatHistoryAgentThread(); - Scanner scanner = new Scanner(System.in); - - while (true) { - System.out.print("> "); - - String input = scanner.nextLine(); - if (input.equalsIgnoreCase("exit")) { - break; - } - - var message = new ChatMessageContent<>(AuthorRole.USER, input); - KernelArguments arguments = KernelArguments.builder() - .withVariable("now", System.currentTimeMillis()) - .build(); - - var response = agent.invokeAsync( - message, - agentThread, - AgentInvokeOptions.builder() - .withKernelArguments(arguments) - .build()) - .block().get(0); - - System.out.println("> " + response.getMessage()); - agentThread = response.getThread(); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/audio/Example82_Audio.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/audio/Example82_Audio.java deleted file mode 100644 index beeebd08e..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/audio/Example82_Audio.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.audio; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.azure.core.util.BinaryData; -import com.microsoft.semantickernel.services.audio.AudioContent; -import com.microsoft.semantickernel.services.audio.AudioToTextExecutionSettings; -import com.microsoft.semantickernel.services.audio.AudioToTextService; -import com.microsoft.semantickernel.services.audio.TextToAudioExecutionSettings; -import com.microsoft.semantickernel.services.audio.TextToAudioService; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; - -public class Example82_Audio { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String TextToAudioModel = "tts-1"; - private static final String AudioToTextModel = "whisper-1"; - - public static void main(String[] args) throws IOException { - System.out.println("======== Example82_Audio ========"); - File file = null; - try { - file = Files.createTempFile("audio", ".mp3").toFile(); - file.deleteOnExit(); - - textToAudioAsync(file); - audioToTextAsync(file); - } finally { - if (file != null) { - file.delete(); - } - } - } - - public static void textToAudioAsync(File audioFile) throws IOException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - var textToAudioService = TextToAudioService.builder() - .withModelId(TextToAudioModel) - .withOpenAIAsyncClient(client) - .build(); - - String sampleText = "Hello, my name is John. I am a software engineer. I am working on a project to convert text to audio."; - - // Set execution settings (optional) - TextToAudioExecutionSettings executionSettings = TextToAudioExecutionSettings.builder() - .withVoice("alloy") - .withResponseFormat("mp3") - .withSpeed(1.0) - .build(); - - // Convert text to audio - AudioContent audioContent = textToAudioService.getAudioContentAsync( - sampleText, - executionSettings) - .block(); - - // Save audio content to a file - Files.write(audioFile.toPath(), audioContent.getData()); - } - - public static void audioToTextAsync(File audioFile) { - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - var textToAudioService = AudioToTextService.builder() - .withModelId(AudioToTextModel) - .withOpenAIAsyncClient(client) - .build(); - byte[] data = BinaryData.fromFile(audioFile.toPath()).toBytes(); - - // Set execution settings (optional) - AudioToTextExecutionSettings executionSettings = AudioToTextExecutionSettings.builder() - .withLanguage("en") - .withPrompt("sample prompt") - .withResponseFormat("json") - .withTemperature(0.3) - .withFilename(audioFile.getName()) - .build(); - - String text = textToAudioService.getTextContentsAsync( - AudioContent.builder() - .withData(data) - .build(), - executionSettings).block(); - - System.out.println(text); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example17_ChatGPT.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example17_ChatGPT.java deleted file mode 100644 index afd68fa7d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example17_ChatGPT.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.azure.core.util.serializer.JsonSerializerProvider; -import com.azure.core.util.serializer.JsonSerializerProviders; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; - -public class Example17_ChatGPT { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Open AI - ChatGPT ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatGPT = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - ChatHistory chatHistory = new ChatHistory("You are a librarian, expert about books"); - - // First user message - chatHistory.addUserMessage("Hi, I'm looking for book suggestions"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - messageOutput(chatHistory); - - chatHistory.addUserMessage( - "I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - messageOutput(chatHistory); - } - - private static void messageOutput(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage().get(); - System.out.println(message.getAuthorRole() + ": " + message.getContent()); - System.out.println("------------------------"); - } - - private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory) { - - var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null) - .block(); - - StringBuilder message = new StringBuilder(); - reply.forEach(chatMessageContent -> message.append(chatMessageContent.getContent())); - chatHistory.addAssistantMessage(message.toString()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example30_ChatWithPrompts.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example30_ChatWithPrompts.java deleted file mode 100644 index 04a7a34fe..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example30_ChatWithPrompts.java +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.TimePlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory; -import com.microsoft.semantickernel.services.ServiceNotFoundException; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.io.FileNotFoundException; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; - -public class Example30_ChatWithPrompts { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws FileNotFoundException, ServiceNotFoundException { - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - System.out.println("======== Chat with prompts ========"); - - /* - * Load 3 files: - * - 30-system-prompt.txt: the system prompt, used to initialize the chat session. - * - 30-user-context.txt: the user context, e.g. a piece of a document the user selected and - * is asking to process. - * - 30-user-prompt.txt: the user prompt, just for demo purpose showing that one can - * leverage the same approach also to augment user messages. - */ - - var systemPromptTemplate = EmbeddedResourceLoader.readFile("30-system-prompt.txt", - Example30_ChatWithPrompts.class); - var selectedText = EmbeddedResourceLoader.readFile("30-user-context.txt", - Example30_ChatWithPrompts.class); - var userPromptTemplate = EmbeddedResourceLoader.readFile("30-user-prompt.txt", - Example30_ChatWithPrompts.class); - - // As an example, we import the time plugin, which is used in system prompt to read the current date. - // We could also use a variable, this is just to show that the prompt can invoke functions. - KernelPlugin timePlugin = KernelPluginFactory.createFromObject( - new TimePlugin(), "time"); - kernel = kernel.toBuilder().withPlugin(timePlugin).build(); - - // Adding required arguments referenced by the prompt templates. - - var arguments = KernelArguments - .builder() - .withVariable("selectedText", selectedText) - .withVariable("startTime", DateTimeFormatter.ofPattern("hh:mm:ss a zz").format( - ZonedDateTime.of(2000, 1, 1, 1, 1, 1, 1, ZoneId.systemDefault()))) - .withVariable("userMessage", "extract locations as a bullet point list") - .build(); - - // Render the system prompt. This string is used to configure the chat. - // This contains the context, ie a piece of a wikipedia page selected by the user. - String systemMessage = PromptTemplateFactory - .build(PromptTemplateConfig.builder().withTemplate(systemPromptTemplate).build()) - .renderAsync(kernel, arguments, null) - .block(); - - System.out.println("------------------------------------\n" + systemMessage); - - // Render the user prompt. This string is the query sent by the user - // This contains the user request, ie "extract locations as a bullet point list" - String userMessage = PromptTemplateFactory - .build(PromptTemplateConfig.builder().withTemplate(userPromptTemplate).build()) - .renderAsync(kernel, arguments, null) - .block(); - - System.out.println("------------------------------------\n" + userMessage); - - // Client used to request answers - var chatCompletion = kernel.getService(ChatCompletionService.class); - - // The full chat history. Depending on your scenario, you can pass the full chat if useful, - // or create a new one every time, assuming that the "system message" contains all the - // information needed. - var chatHistory = new ChatHistory(systemMessage); - - // Add the user query to the chat history - chatHistory.addUserMessage(userMessage); - - // Finally, get the response from AI - var answer = chatCompletion - .getChatMessageContentsAsync(chatHistory, kernel, null) - .block(); - System.out.println( - "------------------------------------\n" + answer.stream().findFirst().get() - .getContent()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example33_Chat.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example33_Chat.java deleted file mode 100644 index 789427da4..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example33_Chat.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.util.List; -import java.util.function.Function; - -// In .net this is streaming, this is a non-streaming example -public class Example33_Chat { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Open AI - ChatGPT Streaming ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatGPT = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - ChatHistory chatHistory = new ChatHistory("You are a librarian, expert about books"); - - // First user message - chatHistory.addUserMessage("Hi, I'm looking for book suggestions"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - - chatHistory.addUserMessage( - "I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory); - } - - private static void messageOutput(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage().get(); - System.out.println(message.getAuthorRole() + ": " + message.getContent()); - System.out.println("------------------------"); - } - - private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory) { - var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null); - System.out.print(AuthorRole.ASSISTANT + ": "); - - String message = reply - .mapNotNull(CollectionUtil::getLastOrNull) - .doOnNext(streamingChatMessage -> { - String content = streamingChatMessage.getContent(); - System.out.print(content); - }) - .map(ChatMessageContent::getContent) - .block(); - - System.out.println("\n------------------------"); - chatHistory.addAssistantMessage(message); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example44_MultiChatCompletion.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example44_MultiChatCompletion.java deleted file mode 100644 index 52cec6e36..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example44_MultiChatCompletion.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; - -public class Example44_MultiChatCompletion { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Open AI - Multiple Chat Completion ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatGPT = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - ChatHistory chatHistory = new ChatHistory("You are a librarian, expert about books"); - var executionSettings = PromptExecutionSettings.builder() - .withMaxTokens(1024) - .withTemperature(1) - .withResultsPerPrompt(2) - .build(); - - chatHistory.addUserMessage("Hi, I'm looking for 3 different book suggestions about sci-fi"); - messageOutput(chatHistory); - - GPTReply(chatGPT, chatHistory, executionSettings); - } - - private static void messageOutput(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage().get(); - System.out.println(message.getAuthorRole() + ": " + message.getContent()); - System.out.println("------------------------"); - } - - private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory, - PromptExecutionSettings settings) { - - var invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings) - .build(); - - var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, invocationContext) - .block(); - - reply.forEach(chatMessageContent -> { - chatHistory.addAssistantMessage(chatMessageContent.getContent()); - messageOutput(chatHistory); - }); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example63_ChatCompletionPrompts.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example63_ChatCompletionPrompts.java deleted file mode 100644 index 88fa9db04..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example63_ChatCompletionPrompts.java +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.util.concurrent.CountDownLatch; - -public class Example63_ChatCompletionPrompts { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws InterruptedException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - String chatPrompt = """ - What is Seattle? - Respond with JSON. - """.stripIndent(); - - var chatSemanticFunction = KernelFunctionFromPrompt.builder() - .withTemplate(chatPrompt).build(); - var chatPromptResult = kernel.invokeAsync(chatSemanticFunction).block(); - - System.out.println("Chat Prompt:"); - System.out.println(chatPrompt); - System.out.println("Chat Prompt Result:"); - System.out.println(chatPromptResult.getResult()); - - CountDownLatch cdl = new CountDownLatch(1); - System.out.println("Chat Prompt Result:"); - kernel - .invokeAsync(chatSemanticFunction) - .doFinally(x -> cdl.countDown()) - .subscribe(result -> System.out.println(result.getResult())); - - cdl.await(); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example96_GeminiChatCompletion.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example96_GeminiChatCompletion.java deleted file mode 100644 index 8b3aac3a4..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example96_GeminiChatCompletion.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.google.cloud.vertexai.VertexAI; -import com.microsoft.semantickernel.aiservices.google.chatcompletion.GeminiChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; - -public class Example96_GeminiChatCompletion { - private static final String PROJECT_ID = System.getenv("PROJECT_ID"); - private static final String LOCATION = System.getenv("LOCATION"); - private static final String MODEL_ID = System.getenv("GEMINI_MODEL_ID"); - - public static void main(String[] args) { - // Authenticate with Google Cloud running: - // gcloud config set project PROJECT_ID - // gcloud auth login ACCOUNT - // - // Or if you want to use an API key follow: - // https://cloud.google.com/docs/authentication/api-keys#using-with-client-libs - - VertexAI client = new VertexAI(PROJECT_ID, LOCATION); - - ChatCompletionService geminiChat = GeminiChatCompletion.builder() - .withVertexAIClient(client) - .withModelId(MODEL_ID) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - ChatHistory chatHistory = new ChatHistory(); - - // First user message - chatHistory.addUserMessage("Hi, I'm looking for book suggestions"); - messageOutput(chatHistory); - - reply(geminiChat, chatHistory); - messageOutput(chatHistory); - - chatHistory.addUserMessage( - "I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); - messageOutput(chatHistory); - - reply(geminiChat, chatHistory); - messageOutput(chatHistory); - } - - private static void messageOutput(ChatHistory chatHistory) { - var message = chatHistory.getLastMessage().get(); - System.out.println(message.getAuthorRole() + ": " + message.getContent()); - System.out.println("------------------------"); - } - - private static void reply(ChatCompletionService geminiChat, ChatHistory chatHistory) { - var reply = geminiChat.getChatMessageContentsAsync(chatHistory, null, null) - .block(); - - StringBuilder message = new StringBuilder(); - reply.forEach(chatMessageContent -> message.append(chatMessageContent.getContent())); - chatHistory.addAssistantMessage(message.toString()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example_ChatWithVision.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example_ChatWithVision.java deleted file mode 100644 index 2c1acbc90..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/Example_ChatWithVision.java +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; - -public class Example_ChatWithVision { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - // NOTE THAT vision is GPT4 only - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - public static void main(String[] args) throws MalformedURLException { - System.out.println("======== Open AI - Chat with Vision ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatGPT = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - describeUrl(chatGPT); - describeImage(chatGPT); - } - - private static void describeImage(ChatCompletionService chatGPT) throws MalformedURLException { - - try (InputStream duke = Example_ChatWithVision.class.getResourceAsStream("duke.png")) { - byte[] image = duke.readAllBytes(); - - ChatHistory chatHistory = new ChatHistory( - "You look at images and answer questions about them"); - - // First user message - chatHistory.addUserMessage( - "This image is a cartoon drawing of the Java Duke character riding a dinosaur. What type of dinosaur is it?"); - chatHistory.addMessage( - ChatMessageImageContent.builder() - .withImage("png", image) - .build()); - - var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null); - - String message = reply - .mapNotNull(CollectionUtil::getLastOrNull) - .map(ChatMessageContent::getContent) - .block(); - - System.out.println("\n------------------------"); - System.out.print(message); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static void describeUrl(ChatCompletionService chatGPT) throws MalformedURLException { - ChatHistory chatHistory = new ChatHistory("You look at images and describe them"); - - // First user message - chatHistory.addUserMessage("Describe the following image"); - chatHistory.addMessage( - ChatMessageImageContent.builder() - .withImageUrl(new URL("https://cr.openjdk.org/~jeff/Duke/jpg/Welcome.jpg")) - .build()); - - var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null); - - String message = reply - .mapNotNull(CollectionUtil::getLastOrNull) - .map(ChatMessageContent::getContent) - .block(); - - System.out.println("\n------------------------"); - System.out.print(message); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java deleted file mode 100644 index 5d0aad36e..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example_ChatWithResponseFormat { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - public static void main(String[] args) throws InterruptedException, JsonProcessingException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - PromptExecutionSettings promptExecutionSettings = PromptExecutionSettings.builder() - .withResponseFormat( - JsonSchemaResponseFormat.builder() - .setResponseFormat(Pet.class) - .setName("Pet") - .build()) - .build(); - - FunctionResult response = kernel - .invokePromptAsync("Generate an example pet that can be used in test code") - .withResultTypeAutoConversion(Pet.class) - .withPromptExecutionSettings(promptExecutionSettings) - .block(); - - System.out.println(new ObjectMapper() - .writerWithDefaultPrettyPrinter() - .writeValueAsString(response.getResult())); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java deleted file mode 100644 index cd227ebd5..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Pet.AnimalType; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Pet.Weight; -import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Pet.WeightUnit; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example_ChatWithResponseFormatToolCall { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - public static void main(String[] args) throws InterruptedException, JsonProcessingException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .withPlugin(KernelPluginFactory.createFromObject(new PetStore(), "PetStore")) - .build(); - - PromptExecutionSettings promptExecutionSettings = PromptExecutionSettings.builder() - .withJsonSchemaResponseFormat(Pet.class) - .build(); - - FunctionResult response = kernel.invokePromptAsync("Get pet with id 1234") - .withResultTypeAutoConversion(Pet.class) - .withPromptExecutionSettings(promptExecutionSettings) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .block(); - - System.out.println(new ObjectMapper() - .writerWithDefaultPrettyPrinter() - .writeValueAsString(response.getResult())); - } - - public static class PetStore { - - @DefineKernelFunction(name = "getPetById", returnType = "com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema.Pet") - public Pet getPetById( - @KernelFunctionParameter(name = "id") String id) { - if (id.equals("1234")) { - return new Pet( - "Test name", - AnimalType.CAT, - 5, - new Weight(5.0, WeightUnit.KG)); - } - return null; - } - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Pet.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Pet.java deleted file mode 100644 index b88a8e53f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Pet.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.responseschema; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Pet { - - private final String name; - private final AnimalType type; - private final int age; - private final Weight weight; - - public static enum AnimalType { - CAT, DOG, FISH - } - - public static enum WeightUnit { - KG, LB - } - - public static class Weight { - - private final double value; - private final WeightUnit unit; - - @JsonCreator - public Weight( - @JsonProperty("value") double value, - @JsonProperty("unit") WeightUnit unit) { - this.value = value; - this.unit = unit; - } - - public double getValue() { - return value; - } - - public WeightUnit getUnit() { - return unit; - } - } - - @JsonCreator - public Pet( - @JsonProperty("name") String name, - @JsonProperty("type") AnimalType type, - @JsonProperty("age") int age, - @JsonProperty("weight") Weight weight) { - this.name = name; - this.type = type; - this.age = age; - this.weight = weight; - } - - public String getName() { - return name; - } - - public AnimalType getType() { - return type; - } - - public int getAge() { - return age; - } - - public Weight getWeight() { - return weight; - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example08_RetryHandler.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example08_RetryHandler.java deleted file mode 100644 index 508d3db45..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example08_RetryHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.configuration; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.http.policy.ExponentialBackoffOptions; -import com.azure.core.http.policy.RetryOptions; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.time.Duration; - -public class Example08_RetryHandler { - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws ConfigurationException { - // Create a Kernel with the HttpClient - RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions() - .setMaxDelay(Duration.ofSeconds(10)) - .setBaseDelay(Duration.ofSeconds(2)) - .setMaxRetries(3)); - - OpenAIAsyncClient client = new OpenAIClientBuilder() - .retryOptions(retryOptions) - .endpoint("https://localhost:5000") - .credential(new AzureKeyCredential("BAD KEY")) - .buildAsyncClient(); - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - String question = "How popular is the Polly library?"; - - KernelFunction function = KernelFunctionFromPrompt.builder() - .withTemplate(question) - .build(); - - try { - // Will retry 3 times with exponential backoff - kernel.invokeAsync(function).block(); - } catch (Exception e) { - System.out.println("Hit max retries"); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example26_AADAuth.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example26_AADAuth.java deleted file mode 100644 index 5e885795a..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example26_AADAuth.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.configuration; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.identity.DeviceCodeCredential; -import com.azure.identity.DeviceCodeCredentialBuilder; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; - -public class Example26_AADAuth { - - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws ConfigurationException { - - DeviceCodeCredential token = new DeviceCodeCredentialBuilder() - .build(); - - OpenAIAsyncClient client = new OpenAIClientBuilder() - .credential(token) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - ChatCompletionService chatService = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatService) - .build(); - - var chatHistory = new ChatHistory(); - - // User message - chatHistory.addUserMessage("Tell me a joke about hourglasses"); - - // Bot reply - var reply = chatService.getChatMessageContentsAsync(chatHistory, kernel, null).block(); - System.out.println(reply); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example41_HttpClientUsage.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example41_HttpClientUsage.java deleted file mode 100644 index 763f0a6cb..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example41_HttpClientUsage.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.configuration; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.http.HttpClient; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; - -public class Example41_HttpClientUsage { - - public static void main(String[] args) { - useDefaultHttpClient(); - useCustomHttpClient(); - } - - ///

- /// Demonstrates the usage of the default HttpClient provided by the SK SDK. - /// - private static void useDefaultHttpClient() { - OpenAIAsyncClient client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential("a-key")) - .endpoint("an-endpoint") - .buildAsyncClient(); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, - OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo-2") - .build()) - .build(); - } - - /// - /// Demonstrates the usage of a custom HttpClient. - /// - private static void useCustomHttpClient() { - HttpClient customHttpClient = HttpClient.createDefault(); - - OpenAIAsyncClient client = new OpenAIClientBuilder() - .httpClient(customHttpClient) - .endpoint("https://localhost:5000") - .credential(new AzureKeyCredential("BAD KEY")) - .buildAsyncClient(); - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId("gpt-35-turbo") - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example58_ConfigureExecutionSettings.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example58_ConfigureExecutionSettings.java deleted file mode 100644 index f6096eb49..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/configuration/Example58_ConfigureExecutionSettings.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.configuration; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.OutputVariable; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example58_ConfigureExecutionSettings { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Example58_ConfigureExecutionSettings ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - var prompt = "Hello AI, what can you do for me?"; - - // Option 1: - // Invoke the prompt function and pass an OpenAI specific instance containing the execution settings - var result = kernel.invokeAsync( - KernelFunctionFromPrompt.builder() - .withTemplate(prompt) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(60) - .withTemperature(0.7) - .build()) - .withOutputVariable(new OutputVariable<>("result", String.class)) - .build()) - .block(); - - System.out.println(result.getResult()); - - // Option 2: - // Load prompt template configuration including the execution settings from a JSON payload - // Create the prompt functions using the prompt template and the configuration (loaded in the previous step) - // Invoke the prompt function using the implicitly set execution settings - String configPayload = """ - { - "schema": 1, - "name": "HelloAI", - "description": "Say hello to an AI", - "type": "completion", - "completion": { - "max_tokens": 256, - "temperature": 0.5, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - } - }""".stripIndent(); - - var promptConfig = PromptTemplateConfig - .parseFromJson(configPayload) - .copy() - .withTemplate(prompt) - .build(); - - var func = KernelFunction - .createFromPrompt(promptConfig) - .build(); - - var result2 = kernel.invokeAsync(func).block(); - System.out.println(result2.getResult()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example01_NativeFunctions.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example01_NativeFunctions.java deleted file mode 100644 index 1e3701e71..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example01_NativeFunctions.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.microsoft.semantickernel.samples.plugins.text.TextPlugin; - -/** - * Demonstrates a native function. - */ -public class Example01_NativeFunctions { - - public static void main(String[] args) { - - // Load native skill - TextPlugin text = new TextPlugin(); - - // Use function without kernel - String result = text.uppercase("ciao!"); - - System.out.println(result); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example03_Arguments.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example03_Arguments.java deleted file mode 100644 index 7db37899c..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example03_Arguments.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.util.Locale; -import reactor.core.publisher.Mono; - -/** - * Demonstrates running a pipeline (a sequence of functions) on a - * {@code com.microsoft.semantickernel.orchestration.SKContext} - */ -public class Example03_Arguments { - - public static void main(String[] args) { - Kernel kernel = Kernel.builder().build(); - - // Load native plugin - KernelPlugin functionCollection = KernelPluginFactory - .createFromObject(new StaticTextPlugin(), "text"); - - KernelArguments arguments = KernelArguments.builder() - .withInput("Today is: ") - .withVariable("day", "Monday") - .build(); - - FunctionResult resultValue = kernel.invokeAsync(functionCollection.get("AppendDay")) - .withArguments(arguments) - .block(); - - System.out.println(resultValue.getResult()); - } - - public static class StaticTextPlugin { - - @DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase", returnType = "java.lang.String") - public static Mono uppercase( - @KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) { - return Mono.just(text.toUpperCase(Locale.ROOT)); - } - - @DefineKernelFunction(description = "Append the day variable", name = "appendDay", returnType = "java.lang.String") - public Mono appendDay( - @KernelFunctionParameter(description = "Text to append to", name = "input") String input, - @KernelFunctionParameter(description = "Current day", name = "day") String day) { - return Mono.just(input + day); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example05_InlineFunctionDefinition.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example05_InlineFunctionDefinition.java deleted file mode 100644 index 52edb0dba..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example05_InlineFunctionDefinition.java +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -public class Example05_InlineFunctionDefinition { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws ConfigurationException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - System.out.println("======== Inline Function Definition ========"); - - // Function defined using few-shot design pattern - String promptTemplate = """ - Generate a creative reason or excuse for the given event. - Be creative and be funny. Let your imagination run wild. - - Event: I am running late. - Excuse: I was being held ransom by giraffe gangsters. - - Event: I haven't been to the gym for a year - Excuse: I've been too busy training my pet dragon. - - Event: {{$input}} - """.stripIndent(); - - var excuseFunction = KernelFunctionFromPrompt.builder() - .withTemplate(promptTemplate) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withTemperature(0.4) - .withTopP(1) - .withMaxTokens(100) - .build()) - .build(); - - var result = kernel - .invokeAsync(excuseFunction) - .withArguments( - KernelArguments.builder() - .withInput("I missed the F1 final race") - .build()) - .block(); - System.out.println(result.getResult()); - - result = kernel.invokeAsync(excuseFunction) - .withArguments( - KernelArguments.builder() - .withInput("sorry I forgot your birthday") - .build()) - .block(); - System.out.println(result.getResult()); - - var date = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC) - .format(Instant.ofEpochSecond(1)); - var message = "Translate this date " + date + " to French format"; - var fixedFunction = KernelFunction.createFromPrompt(message) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(100) - .build()) - .build(); - - FunctionResult fixedFunctionResult = kernel - .invokeAsync(fixedFunction) - .block(); - System.out.println(fixedFunctionResult.getResult()); - - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example09_FunctionTypes.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example09_FunctionTypes.java deleted file mode 100644 index 92aab5548..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example09_FunctionTypes.java +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter.NoopConverter; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -import java.nio.file.Path; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.Temporal; -import java.util.Date; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import reactor.core.publisher.Mono; - -public class Example09_FunctionTypes { - - private static final String PLUGIN_DIR = System.getenv("PLUGIN_DIR") == null ? "." - : System.getenv("PLUGIN_DIR"); - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws InterruptedException { - - System.out.println("======== Method Function types ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - // Load native plugin into the kernel function collection, sharing its functions with prompt templates - KernelPlugin plugin = KernelPluginFactory - .createFromObject(new LocalExamplePlugin(), "Examples"); - - KernelPlugin summarize = KernelPluginFactory - .importPluginFromDirectory( - Path.of(PLUGIN_DIR, - "samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins"), - "SummarizePlugin", - null); - - KernelPlugin examplePlugin = KernelPluginFactory - .importPluginFromResourcesDirectory( - "Plugins", - "ExamplePlugins", - "ExampleFunctionRoot", - null, - Example09_FunctionTypes.class); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .withPlugin(plugin) - .withPlugin(summarize) - .withPlugin(examplePlugin) - .build(); - - // Different ways to invoke a function (not limited to these examples) - FunctionResult result = kernel.invokeAsync(plugin.get("NoInputWithVoidResult")) - .block(); - assert result == null; - - CountDownLatch cdl = new CountDownLatch(1); - - kernel - .invokeAsync(plugin.get("NoInputWithVoidResult")) - .doFinally(ignore -> cdl.countDown()) - .subscribe(ignore -> { - throw new RuntimeException("No return expected"); - }); - - cdl.await(); - - System.out.println(result != null ? result.getResult() : "null"); - result = kernel.invokeAsync(plugin.get("NoInputTaskWithVoidResult")) - .block(); - assert result == null; - System.out.println(result != null ? result.getResult() : "null"); - - result = kernel - .invokeAsync(plugin.get("InputDateTimeWithStringResult")) - .withArguments( - KernelArguments - .builder() - .withVariable("currentDate", - ContextVariable.of( - ZonedDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC), - new DateTimeContextVariableTypeConverter())) - .build()) - .block(); - System.out.println(result.getResult()); - - result = kernel.invokeAsync(plugin.get("NoInputTaskWithStringResult")) - .block(); - System.out.println(result.getResult()); - - result = kernel.invokeAsync(plugin.get("MultipleInputsWithVoidResult")) - .withArguments( - KernelArguments - .builder() - .withVariable("x", "x string") - .withVariable("y", 100) - .withVariable("z", 1.5) - .build()) - .block(); - - result = kernel - .invokeAsync(plugin.get("ComplexInputWithStringResult")) - .withArguments( - KernelArguments - .builder() - .withVariable( - "complexObject", - ContextVariable.of( - new Object() { - @Override - public String toString() { - return "A complex object"; - } - }, - new NoopConverter<>(Object.class))) - .build()) - .block(); - System.out.println(result.getResult()); - - result = kernel - .invokeAsync(plugin.get("InputStringTaskWithStringResult")) - .withArguments( - KernelArguments - .builder() - .withVariable("echoInput", "return this") - .build()) - .block(); - System.out.println(result.getResult()); - - result = kernel - .invokeAsync(plugin.get("InputStringTaskWithVoidResult")) - .withArguments( - KernelArguments - .builder() - .withVariable("x", "x input") - .build()) - .block(); - assert result == null; - System.out.println(result != null ? result.getResult() : "null"); - - result = kernel - .invokeAsync(plugin.get("noInputComplexReturnTypeAsync")) - .block(); - System.out.println(result.getResult()); - - var temporalResult = kernel - .invokeAsync(plugin.get("noInputComplexReturnType")) - .block(); - System.out.println(temporalResult.getResult()); - - // Possibilities for return type combinations: - // | Method return type | Declared Function Return Type | Invocation Return type | - // |--------------------|-------------------------------|------------------------| - // | T | T | T | - // | T | T | V converted from T | - - // | T | U extends T | T | - // | T | U extends T | U | - // | T | U extends T | V converted from U | - - var result1 = kernel - .invokeAsync(plugin.get("conversionScenarioA")) - .block(); - System.out.println(result1.getResult()); - - var result2 = kernel - .invokeAsync(plugin.get("conversionScenarioA")) - .block(); - System.out.println(result2.getResult()); - - var result3 = kernel - .invokeAsync(plugin.get("conversionScenarioB")) - .block(); - System.out.println(result3.getResult()); - - var result4 = kernel - .invokeAsync(plugin.get("conversionScenarioB")) - .block(); - System.out.println(result4.getResult()); - - var result5 = kernel - .invokeAsync(plugin.get("conversionScenarioB")) - .block(); - System.out.println(result5.getResult()); - - var result6 = kernel - .invokeAsync(plugin.get("noInputComplexReturnType")) - .block(); - System.out.println(result6.getResult()); - - var result7 = kernel - .invokeAsync(plugin.get("withDefaultValue")) - .block(); - System.out.println(result7.getResult()); - - var result8 = kernel - .invokeAsync(plugin.get("noInputComplexReturnType")) - .withResultType( - new ContextVariableType<>( - new DateTimeContextVariableTypeConverter(), - ZonedDateTime.class)) - .block(); - System.out.println(result8.getResult()); - - var result9 = kernel - .invokeAsync(plugin.get("noInputComplexReturnType")) - .withResultType( - new ContextVariableType<>( - new DateTimeContextVariableTypeConverter(), - ZonedDateTime.class)) - .block(); - System.out.println(result9.getResult()); - - result = kernel.invokeAsync(plugin.get("MultipleComplexInputsWithVoidResult")) - .withArguments( - KernelArguments - .builder() - .withVariable("x", OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)) - .withVariable("y", OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)) - .build()) - .withTypeConverter(new DateTimeContextVariableTypeConverter()) - .block(); - - var result10 = kernel - .invokeAsync(plugin.get("WithPrimitiveReturnType")) - .block(); - System.out.println(result10.getResult()); - - var result11 = kernel - .invokeAsync(plugin.get("WithBoxedPrimitiveReturnType")) - .block(); - System.out.println(result11.getResult()); - - var result12 = kernel - .invokeAsync(plugin.get("AsyncWithBoxedPrimitiveReturnType")) - .block(); - System.out.println(result12.getResult()); - - var result13 = kernel - .invokeAsync(plugin.get("WithEmptyListReturn")) - .block(); - System.out.println(result13.getResult()); - - var result14 = kernel - .invokeAsync(plugin.get("WithListReturn")) - .block(); - System.out.println(result14.getResult()); - - var result15 = kernel - .invokeAsync(plugin.get("WithListReturn2")) - .block(); - System.out.println(result15.getResult()); - - var result16 = kernel - .invokeAsync(plugin.get("WithListReturn3")) - .block(); - System.out.println(result16.getResult()); - - /* - * TODO: support FunctionResult - * kernel - * .invokeAsync(plugin.get("NoInputWithFunctionResult"), - * null, - * Void.class) - * .block(); - * - */ - - /* - * TODO: support injection - * // Injecting Parameters Examples - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingKernelFunctionWithStringResult)]); - * await - * kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.TaskInjectingLoggerWithNoResult)]); - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingLoggerFactoryWithNoResult)]); - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingCultureInfoOrIFormatProviderWithStringResult)]); - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingCancellationTokenWithStringResult)]); - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingServiceSelectorWithStringResult)]); - * await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin. - * TaskInjectingKernelWithInputTextAndStringResult)], - * new() - * { - * ["textToSummarize"] = @"C# is a modern, versatile language by Microsoft, blending the - * efficiency of C++ - * with Visual Basic's simplicity. It's ideal for a wide range of applications, - * emphasizing type safety, modularity, and modern programming paradigms." - * }); - * - */ - - // You can also use the kernel.Plugins collection to invoke a function - kernel - .invokeAsync( - kernel.getFunction("Examples", "NoInputWithVoidResult")) - .block(); - } - - private static class DateTimeContextVariableTypeConverter extends - ContextVariableTypeConverter { - - private static final List> converters = List.of( - new DefaultConverter<>(ZonedDateTime.class, Date.class) { - @Override - public Date toObject(ZonedDateTime zonedDateTime) { - return new Date(zonedDateTime.toInstant().toEpochMilli()); - } - }, - new DefaultConverter<>(ZonedDateTime.class, String.class) { - @Override - public String toObject(ZonedDateTime zonedDateTime) { - return zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME); - } - }); - - public DateTimeContextVariableTypeConverter() { - super( - ZonedDateTime.class, - (x) -> { - if (x instanceof OffsetDateTime) { - return ((OffsetDateTime) x).toZonedDateTime(); - } - return convert(x, ZonedDateTime.class); - }, - zonedDateTime -> zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME), - promptString -> ZonedDateTime.parse(promptString, DateTimeFormatter.ISO_DATE_TIME), - converters); - } - } - - public static class LocalExamplePlugin { - - /// - /// Example of using a void function with no input - /// - @DefineKernelFunction(name = "NoInputWithVoidResult", returnType = "void") - public void NoInputWithVoidResult() { - System.out.println("Running this.NoInputWithVoidResult) -> No input"); - } - - /// - /// Example of using a void task function with no input - /// - @DefineKernelFunction(name = "NoInputTaskWithVoidResult", returnType = "java.lang.Void") - public Mono NoInputTaskWithVoidResult() { - return Mono.fromRunnable( - () -> System.out.println("Running this.NoInputTaskWithVoidResult) -> No input")); - } - - /// - /// Example of using a function with a DateTime input and a string result - /// - @DefineKernelFunction(name = "InputDateTimeWithStringResult", returnType = "java.lang.String") - public String InputDateTimeWithStringResult( - @KernelFunctionParameter(name = "currentDate", description = "Current date time", type = ZonedDateTime.class) ZonedDateTime currentDate) { - var result = currentDate.format(DateTimeFormatter.ISO_DATE_TIME); - System.out.println( - "Running {nameof(this.InputDateTimeWithStringResult)} -> [currentDate = {" - + currentDate + "}] -> result: {" + result + "}"); - return result; - } - - /// - /// Example of using a Task function with no input and a string result - /// - @DefineKernelFunction(name = "NoInputTaskWithStringResult", returnType = "java.lang.String") - public Mono NoInputTaskWithStringResult() { - return Mono.fromCallable(() -> { - var result = "string result"; - System.out.println( - "Running {nameof(this.NoInputTaskWithStringResult)} -> No input -> result: {" - + result + "}"); - return result; - }); - } - - /// - /// Example passing multiple parameters with multiple types - /// - @DefineKernelFunction(name = "MultipleInputsWithVoidResult") - public void MultipleInputsWithVoidResult( - @KernelFunctionParameter(name = "x") String x, - - @KernelFunctionParameter(name = "y", type = int.class) int y, - - @KernelFunctionParameter(name = "z", type = double.class) double z) { - System.out.println( - "Running {nameof(this.MultipleInputsWithVoidResult)} -> input: [x = {" + x - + "}, y = {" + y + "}, z = {" + z + "}]"); - } - - /// - /// Example passing a complex object and returning a string result - /// - @DefineKernelFunction(name = "ComplexInputWithStringResult") - public String ComplexInputWithStringResult( - @KernelFunctionParameter(name = "complexObject", type = Object.class) Object complexObject) { - String result = complexObject.toString(); - System.out.println( - "Running {nameof(this.ComplexInputWithStringResult)} -> input: [complexObject = " - + complexObject + "] -> result: {" - + result + "}"); - return result; - } - - /// - /// Example using an async task function echoing the input - /// - @DefineKernelFunction(name = "InputStringTaskWithStringResult", returnType = "java.lang.String") - public Mono InputStringTaskWithStringResult( - - @KernelFunctionParameter(name = "echoInput") String echoInput) { - return Mono.fromCallable(() -> { - System.out.println( - "Running {nameof(this.InputStringTaskWithStringResult)} -> input: [echoInput = " - + echoInput + "] -> result: {" - + echoInput + "}"); - return echoInput; - }); - } - - /// - /// Example using an async void task with string input - /// - @DefineKernelFunction(name = "InputStringTaskWithVoidResult", returnType = "java.lang.Void") - public Mono InputStringTaskWithVoidResult( - @KernelFunctionParameter(name = "x") String x) { - return Mono.fromRunnable(() -> { - System.out.println( - "Running {nameof(this.InputStringTaskWithVoidResult)} -> input: [x = {" + x - + "}]"); - }); - } - - @DefineKernelFunction(name = "noInputComplexReturnTypeAsync", returnType = "java.time.temporal.Temporal") - public Mono noInputComplexReturnTypeAsync() { - return Mono.just( - OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)); - } - - @DefineKernelFunction(name = "noInputComplexReturnType", returnType = "java.time.temporal.Temporal") - public OffsetDateTime noInputComplexReturnType() { - return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC); - } - - @DefineKernelFunction(name = "withDefaultValue", returnType = "java.lang.String") - public String withDefaultValue( - @KernelFunctionParameter(name = "x", defaultValue = "1", type = int.class) int x) { - return Integer.toString(x); - } - - // Possibilities for return type combinations: - // | Method return type | Declared Function Return Type | - // |--------------------|-------------------------------| - // | T | T | - // | T | U extends T | - @DefineKernelFunction(name = "conversionScenarioA", returnType = "java.time.OffsetDateTime") - public OffsetDateTime conversionScenarioA() { - return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC); - } - - @DefineKernelFunction(name = "conversionScenarioB", returnType = "java.time.temporal.Temporal") - public OffsetDateTime conversionScenarioB() { - return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC); - } - - @DefineKernelFunction(name = "MultipleComplexInputsWithVoidResult") - public void MultipleComplexInputsWithVoidResult( - @KernelFunctionParameter(name = "x", type = ZonedDateTime.class) ZonedDateTime x, - - @KernelFunctionParameter(name = "y", type = ZonedDateTime.class) ZonedDateTime y) { - System.out.println( - "Running {nameof(this.MultipleComplexInputsWithVoidResult)} -> input: [x = {" + x - + "}, y = {" + y + "}]"); - } - - @DefineKernelFunction(name = "WithPrimitiveReturnType", returnType = "int") - public int WithPrimitiveReturnType() { - return 1; - } - - @DefineKernelFunction(name = "WithBoxedPrimitiveReturnType", returnType = "int") - public Integer WithBoxedPrimitiveReturnType() { - return Integer.valueOf(1); - } - - @DefineKernelFunction(name = "AsyncWithBoxedPrimitiveReturnType", returnType = "int") - public Mono AsyncWithBoxedPrimitiveReturnType() { - return Mono.just(Integer.valueOf(1)); - } - - @DefineKernelFunction(name = "WithEmptyListReturn") - public List WithEmptyListReturn() { - return List.of(); - } - - @DefineKernelFunction(name = "WithListReturn") - public List WithListReturn() { - return List.of(1, 2, 3); - } - - @DefineKernelFunction(name = "WithListReturn2", returnType = "java.util.List") - public List WithListReturn2() { - return List.of(1, 2, 3); - } - - @DefineKernelFunction(name = "WithListReturn3", returnType = "java.util.List") - public Mono> WithListReturn3() { - return Mono.just(List.of(1, 2, 3)); - } - - /* - * /// - * /// Example using a function to return the result of another inner function - * /// - * - * @DefineKernelFunction(name = "InputStringTaskWithVoidResult") - * public FunctionResult NoInputWithFunctionResult() - * { - * var myInternalFunction = KernelFunctionFactory.CreateFromMethod(() => { }); - * var result = new FunctionResult(myInternalFunction); - * Console.WriteLine( - * $"Running {nameof(this.NoInputWithFunctionResult)} -> No input -> result: {result.GetType().Name}" - * ); - * return result; - * } - */ - - /* - * - * /// - * /// Example using a task function to return the result of another kernel function - * /// - * [KernelFunction] - * public async Task NoInputTaskWithFunctionResult(Kernel kernel) - * { - * var result = await - * kernel.InvokeAsync(kernel.Plugins["Examples"][nameof(this.NoInputWithVoidResult)]); - * Console.WriteLine( - * $"Running {nameof(this.NoInputTaskWithFunctionResult)} -> Injected kernel -> result: {result.GetType().Name}" - * ); - * return result; - * } - * - * /// - * /// Example how to inject Kernel in your function - * /// This example uses the injected kernel to invoke a plugin from within another function - * /// - * [KernelFunction] - * public async Task TaskInjectingKernelWithInputTextAndStringResult(Kernel kernel, - * string textToSummarize) - * { - * var summary = await - * kernel.InvokeAsync(kernel.Plugins["SummarizePlugin"]["Summarize"], new() { - * ["input"] = textToSummarize }); - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected kernel + input: [textToSummarize: {textToSummarize[..15]}...{textToSummarize[^15..]}] -> result: {summary}" - * ); - * return summary!; - * } - * - * /// - * /// Example how to inject the executing KernelFunction as a parameter - * /// - * [KernelFunction, Description("Example function injecting itself as a parameter")] - * public async Task TaskInjectingKernelFunctionWithStringResult(KernelFunction - * executingFunction) - * { - * var result = - * $"Name: {executingFunction.Name}, Description: {executingFunction.Description}"; - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Function -> result: {result}" - * ); - * return result; - * } - * - * /// - * /// Example how to inject ILogger in your function - * /// - * [KernelFunction] - * public Task TaskInjectingLoggerWithNoResult(ILogger logger) - * { - * logger.LogWarning("Running {FunctionName} -> Injected Logger", - * nameof(this.TaskInjectingLoggerWithNoResult)); - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger" - * ); - * return Task.CompletedTask; - * } - * - * /// - * /// Example how to inject ILoggerFactory in your function - * /// - * [KernelFunction] - * public Task TaskInjectingLoggerFactoryWithNoResult(ILoggerFactory loggerFactory) - * { - * loggerFactory - * .CreateLogger() - * .LogWarning("Running {FunctionName} -> Injected Logger", - * nameof(this.TaskInjectingLoggerWithNoResult)); - * - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger" - * ); - * return Task.CompletedTask; - * } - * - * /// - * /// Example how to inject a service selector in your function and use a specific service - * /// - * [KernelFunction] - * public async Task TaskInjectingServiceSelectorWithStringResult(Kernel kernel, - * KernelFunction function, KernelArguments arguments, IAIServiceSelector serviceSelector) - * { - * ChatMessageContent? chatMessageContent = null; - * if (serviceSelector.TrySelectAIService(kernel, function, - * arguments, out var chatCompletion, out var executionSettings)) - * { - * chatMessageContent = await chatCompletion.GetChatMessageContentAsync(new - * ChatHistory("How much is 5 + 5 ?"), executionSettings); - * } - * - * var result = chatMessageContent?.Content; - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Kernel, KernelFunction, KernelArguments, Service Selector -> result: {result}" - * ); - * return result ?? string.Empty; - * } - * - * /// - * /// Example how to inject CultureInfo or IFormatProvider in your function - * /// - * public async Task - * TaskInjectingCultureInfoOrIFormatProviderWithStringResult(CultureInfo cultureInfo, - * IFormatProvider formatProvider) - * { - * var result = - * $"Culture Name: {cultureInfo.Name}, FormatProvider Equals CultureInfo?: {formatProvider.Equals(cultureInfo)}" - * ; - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected CultureInfo, IFormatProvider -> result: {result}" - * ); - * return result; - * } - * - * /// - * /// Example how to inject current CancellationToken in your function - * /// - * [KernelFunction] - * public async Task - * TaskInjectingCancellationTokenWithStringResult(CancellationToken cancellationToken) - * { - * var result = $"Cancellation requested: {cancellationToken.IsCancellationRequested}"; - * Console.WriteLine( - * $"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected Cancellation Token -> result: {result}" - * ); - * return result; - * } - * - * public override string ToString() - * { - * return "Complex type result ToString override"; - * } - * - */ - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example27_PromptFunctionsUsingChatGPT.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example27_PromptFunctionsUsingChatGPT.java deleted file mode 100644 index 1f139e2ff..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example27_PromptFunctionsUsingChatGPT.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example27_PromptFunctionsUsingChatGPT { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - System.out.println("======== Using Chat GPT model for text generation ========"); - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - var func = KernelFunction.createFromPrompt( - "List the two planets closest to '{{$input}}', excluding moons, using bullet points.") - .build(); - - var result = func.invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withVariable("input", "Jupiter") - .build()) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class)) - .block(); - System.out.println(result.getResult()); - - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java deleted file mode 100644 index e921bb784..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.nio.charset.StandardCharsets; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; - -public class Example59_OpenAIFunctionCalling { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - // Define functions that can be called by the model - public static class HelperFunctions { - - @DefineKernelFunction(name = "currentUtcTime", description = "Retrieves the current time in UTC.") - public String currentUtcTime() { - return ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME); - } - - @DefineKernelFunction(name = "getWeatherForCity", description = "Gets the current weather for the specified city") - public String getWeatherForCity( - @KernelFunctionParameter(name = "cityName", description = "Name of the city") String cityName) { - switch (cityName) { - case "Thrapston": - return "80 and sunny"; - case "Boston": - return "61 and rainy"; - case "London": - return "55 and cloudy"; - case "Miami": - return "80 and sunny"; - case "Paris": - return "60 and rainy"; - case "Tokyo": - return "50 and sunny"; - case "Sydney": - return "75 and sunny"; - case "Tel Aviv": - return "80 and sunny"; - default: - return "31 and snowing"; - } - } - } - - public static void main(String[] args) throws NoSuchMethodException { - System.out.println("======== Open AI - Function calling ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var plugin = KernelPluginFactory.createFromObject(new HelperFunctions(), "HelperFunctions"); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin(plugin) - .build(); - - System.out.println("======== Example 1: Use automated function calling ========"); - - var function = KernelFunctionFromPrompt.builder() - .withTemplate( - "Given the current time of day and weather, what is the likely color of the sky in Boston?") - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withTemperature(0.4) - .withTopP(1) - .withMaxTokens(100) - .build()) - .build(); - - var result = kernel - .invokeAsync(function) - .withFunctionChoiceBehavior(FunctionChoiceBehavior.auto(true)) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class)) - .block(); - System.out.println(result.getResult()); - - System.out.println("======== Example 2: Use manual function calling ========"); - - var chatHistory = new ChatHistory(); - chatHistory.addUserMessage( - "Given the current time of day and weather, what is the likely color of the sky in Boston?"); - - while (true) { - var messages = chat.getChatMessageContentsAsync( - chatHistory, - kernel, - InvocationContext.builder() - .withFunctionChoiceBehavior(FunctionChoiceBehavior.auto(false)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .build()) - .block(); - - chatHistory = new ChatHistory(messages); - - ChatMessageContent lastMessage = CollectionUtil.getLastOrNull(messages); - - List toolCalls = null; - - if (lastMessage instanceof OpenAIChatMessageContent) { - toolCalls = ((OpenAIChatMessageContent) lastMessage).getToolCall(); - } - - if (toolCalls == null || toolCalls.isEmpty()) { - break; - } - - for (OpenAIFunctionToolCall toolCall : toolCalls) { - String content; - try { - // getFunction will throw an exception if the function is not found - var fn = kernel.getFunction(toolCall.getPluginName(), - toolCall.getFunctionName()); - FunctionResult fnResult = fn - .invokeAsync(kernel, toolCall.getArguments(), null, null).block(); - content = (String) fnResult.getResult(); - } catch (IllegalArgumentException e) { - content = "Unable to find function. Please try again!"; - } - - chatHistory.addMessage( - AuthorRole.TOOL, - content, - StandardCharsets.UTF_8, - FunctionResultMetadata.build(toolCall.getId())); - } - } - - chatHistory.getMessages().stream() - .filter(it -> it.getContent() != null) - .forEach(it -> System.out.println(it.getContent())); - - multiTurnaroundCall(); - } - - public static class PetPlugin { - - @DefineKernelFunction(name = "getPetName", description = "Retrieves the pet for a given ID.") - public String getPetName( - @KernelFunctionParameter(name = "petId", description = "The pets id") String id) { - if (id.equals("ca2fc6bc-1307-4da6-a009-d7bf88dec37b")) { - return "Snuggles"; - } - - throw new RuntimeException("Pet not found"); - } - - @DefineKernelFunction(name = "getPetType", description = "Retrieves the type of pet for a given ID.") - public String getPetType( - @KernelFunctionParameter(name = "petId", description = "The pets id") String id) { - if (id.equals("ca2fc6bc-1307-4da6-a009-d7bf88dec37b")) { - return "cat"; - } - - throw new RuntimeException("Pet not found"); - } - } - - public static void multiTurnaroundCall() { - System.out.println("======== Open AI - Function calling ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var plugin = KernelPluginFactory.createFromObject(new PetPlugin(), "PetPlugin"); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin(plugin) - .build(); - - System.out.println("======== Example 3: Multiple auto function calling ========"); - - var chatHistory = new ChatHistory(); - chatHistory.addUserMessage( - "What is the name of the pet with id ca2fc6bc-1307-4da6-a009-d7bf88dec37b?"); - - var messages = chat.getChatMessageContentsAsync( - chatHistory, - kernel, - InvocationContext.builder() - .withFunctionChoiceBehavior(FunctionChoiceBehavior.auto(true)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .build()) - .block(); - - chatHistory = new ChatHistory(messages); - - System.out.println(chatHistory.getLastMessage().get().getContent()); - - chatHistory.addMessage(AuthorRole.USER, "What type of animal are they?"); - - messages = chat.getChatMessageContentsAsync( - chatHistory, - kernel, - InvocationContext.builder() - .withFunctionChoiceBehavior(FunctionChoiceBehavior.auto(true)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .build()) - .block(); - - chatHistory = new ChatHistory(messages); - - System.out.println(chatHistory.getLastMessage().get().getContent()); - - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example60_AdvancedMethodFunctions.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example60_AdvancedMethodFunctions.java deleted file mode 100644 index dfbaeb722..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example60_AdvancedMethodFunctions.java +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import reactor.core.publisher.Mono; - -public class Example60_AdvancedMethodFunctions { - - public static void main(String[] args) { - System.out.println("======== Example60_AdvancedMethodFunctions ========"); - - var kernel = Kernel.builder().build(); - - System.out.println("Running Method Function Chaining example..."); - - var functions = KernelPluginFactory.createFromObject( - new FunctionsChainingPlugin(), - FunctionsChainingPlugin.PluginName); - - kernel = kernel.toBuilder() - .withPlugin(functions) - .build(); - - ContextVariableTypeConverter type = new ContextVariableTypeConverter<>( - MyCustomType.class, - o -> (MyCustomType) o, - o -> o.text + " " + o.number, - s -> null); - - ContextVariableTypes.addGlobalConverter(type); - - var result = kernel - .invokeAsync(FunctionsChainingPlugin.PluginName, "Function1") - .withArguments( - KernelArguments - .builder() - .build()) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(MyCustomType.class)) - .block(); - - System.out.println("CustomType.Number: " + result.getResult().number); // 2 - System.out.println( - "CustomType.Text: " + result.getResult().text); // From Function1 + From Function2 - - } - - /// - /// In order to use custom types, should be specified, - /// that will convert object instance to string representation. - /// - /// - /// is used to represent complex object as meaningful string, so - /// it can be passed to AI for further processing using prompt functions. - /// It's possible to choose any format (e.g. XML, JSON, YAML) to represent your object. - /// - public static class MyCustomType { - - public int number; - public String text; - - public MyCustomType(int i, String text) { - this.number = i; - this.text = text; - } - } - - /// - /// Plugin example with two method functions, where one function is called from another. - /// - - public static class FunctionsChainingPlugin { - - public static final String PluginName = "FunctionsChainingPlugin"; - - @DefineKernelFunction(name = "Function1", returnType = "com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions$MyCustomType") - public Mono function1Async(Kernel kernel) { - // Execute another function - return kernel - .invokeAsync(PluginName, "Function2") - .withArguments(KernelArguments.builder().build()) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass( - Example60_AdvancedMethodFunctions.MyCustomType.class)) - .flatMap(value -> { - // Process the result - return Mono.just( - new MyCustomType( - 2 * value.getResult().number, - "From Function1 + " + value.getResult().text)); - }); - } - - @DefineKernelFunction(name = "Function2", returnType = "com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions$MyCustomType") - public MyCustomType function2() { - return new MyCustomType(1, "From Function2"); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example98_GeminiFunctionCalling.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example98_GeminiFunctionCalling.java deleted file mode 100644 index b585775db..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example98_GeminiFunctionCalling.java +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.functions; - -import com.google.cloud.vertexai.VertexAI; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.google.chatcompletion.GeminiChatCompletion; -import com.microsoft.semantickernel.aiservices.google.chatcompletion.GeminiChatMessageContent; -import com.microsoft.semantickernel.aiservices.google.chatcompletion.GeminiFunctionCall; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; - -public class Example98_GeminiFunctionCalling { - private static final String PROJECT_ID = System.getenv("PROJECT_ID"); - private static final String LOCATION = System.getenv("LOCATION"); - private static final String MODEL_ID = System.getenv("GEMINI_MODEL_ID"); - - // Define functions that can be called by the model - public static class HelperFunctions { - - @DefineKernelFunction(name = "currentUtcTime", description = "Retrieves the current time in UTC.") - public String currentUtcTime() { - return ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME); - } - - @DefineKernelFunction(name = "getWeatherForCity", description = "Gets the current weather for the specified city") - public String getWeatherForCity( - @KernelFunctionParameter(name = "cityName", description = "Name of the city") String cityName) { - switch (cityName) { - case "Thrapston": - return "80 and sunny"; - case "Boston": - return "61 and rainy"; - case "London": - return "55 and cloudy"; - case "Miami": - return "80 and sunny"; - case "Paris": - return "60 and rainy"; - case "Tokyo": - return "50 and sunny"; - case "Sydney": - return "75 and sunny"; - case "Tel Aviv": - return "80 and sunny"; - default: - return "31 and snowing"; - } - } - - public static void main(String[] args) throws NoSuchMethodException { - System.out.println("======== Gemini - Function calling ========"); - - VertexAI client = new VertexAI(PROJECT_ID, LOCATION); - - ChatCompletionService chat = GeminiChatCompletion.builder() - .withModelId(MODEL_ID) - .withVertexAIClient(client) - .build(); - - var plugin = KernelPluginFactory.createFromObject(new HelperFunctions(), - "HelperFunctions"); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin(plugin) - .build(); - - System.out.println("======== Example 1: Use automated function calling ========"); - - var function = KernelFunctionFromPrompt.builder() - .withTemplate( - "Given the current time of day and weather, what is the likely color of the sky in Boston?") - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withTemperature(0.4) - .withTopP(1) - .withMaxTokens(100) - .build()) - .build(); - - var result = kernel - .invokeAsync(function) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class)) - .block(); - - System.out.println(result.getResult()); - - System.out.println("======== Example 2: Use manual function calling ========"); - - var chatHistory = new ChatHistory(); - chatHistory.addUserMessage( - "Given the current time of day and weather, what is the likely color of the sky in Boston?"); - - while (true) { - var message = (GeminiChatMessageContent) chat.getChatMessageContentsAsync( - chatHistory, - kernel, - InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(false)) - .withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY) - .build()) - .block().get(0); - - // Add the assistant's response to the chat history - chatHistory.addMessage(message); - if (message.getContent() != null && !message.getContent().isEmpty()) { - System.out.println(message.getContent()); - } - - // Process the functions calls or break if there are no more functions to call - if (message.getGeminiFunctionCalls().isEmpty()) { - break; - } - - List functionResponses = new ArrayList<>(); - for (var geminiFunction : message.getGeminiFunctionCalls()) { - - String content = null; - try { - // getFunction will throw an exception if the function is not found - var fn = kernel.getFunction(geminiFunction.getPluginName(), - geminiFunction.getFunctionName()); - - var arguments = KernelArguments.builder(); - geminiFunction.getFunctionCall().getArgs().getFieldsMap() - .forEach((key, value) -> { - arguments.withVariable(key, value.getStringValue()); - }); - - // Invoke the function and add the result to the list of function responses - FunctionResult functionResult = fn - .invokeAsync(kernel, arguments.build(), null, null).block(); - - functionResponses.add(new GeminiFunctionCall( - geminiFunction.getFunctionCall(), functionResult)); - } catch (IllegalArgumentException e) { - content = "Unable to find function. Please try again!"; - } - } - - // Add the function responses to the chat history - ChatMessageContent functionResponsesMessage = new GeminiChatMessageContent<>( - AuthorRole.USER, - "", null, null, null, null, functionResponses); - - chatHistory.addMessage(functionResponsesMessage); - } - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/CustomTypes_Example.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/CustomTypes_Example.java deleted file mode 100644 index fcf2cc812..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/CustomTypes_Example.java +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.java; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.contextvariables.converters.ContextVariableJacksonConverter; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class CustomTypes_Example { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo-2"); - - public static void main(String[] args) throws ConfigurationException, IOException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - exampleBuildingCustomConverter(chatCompletionService); - exampleUsingJackson(chatCompletionService); - exampleUsingGlobalTypes(chatCompletionService); - } - - public record Pet(String name, int age, String species) { - - @JsonCreator - public Pet( - @JsonProperty("name") String name, - @JsonProperty("age") int age, - @JsonProperty("species") String species) { - this.name = name; - this.age = age; - this.species = species; - } - - @Override - public String toString() { - return name + " " + species + " " + age; - } - } - - private static void exampleBuildingCustomConverter( - ChatCompletionService chatCompletionService) { - Pet sandy = new Pet("Sandy", 3, "Dog"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - - // Format: - // name: Sandy - // age: 3 - // species: Dog - - // Custom serializer - Function petToString = pet -> "name: " + pet.name() + "\n" + - "age: " + pet.age() + "\n" + - "species: " + pet.species() + "\n"; - - // Custom deserializer - Function stringToPet = prompt -> { - Map properties = Arrays.stream(prompt.split("\n")) - .collect(Collectors.toMap( - line -> line.split(":")[0].trim(), - line -> line.split(":")[1].trim())); - - return new Pet( - properties.get("name"), - Integer.parseInt(properties.get("age")), - properties.get("species")); - }; - - // create custom converter - ContextVariableTypeConverter typeConverter = ContextVariableTypeConverter.builder( - Pet.class) - .toPromptString(petToString) - .fromPromptString(stringToPet) - .build(); - - Pet updated = kernel.invokePromptAsync( - "Change Sandy's name to Daisy:\n{{$Sandy}}", - KernelArguments.builder() - .withVariable("Sandy", sandy, typeConverter) - .build()) - .withTypeConverter(typeConverter) - .withResultType(Pet.class) - .block() - .getResult(); - - System.out.println("Sandy's updated record: " + updated); - } - - public static void exampleUsingJackson(ChatCompletionService chatCompletionService) { - Pet sandy = new Pet("Sandy", 3, "Dog"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - - // Create a converter that defaults to using jackson for serialization - ContextVariableTypeConverter typeConverter = ContextVariableJacksonConverter.create( - Pet.class); - - // Invoke the prompt with the custom converter - Pet updated = kernel.invokePromptAsync( - "Increase Sandy's age by a year:\n{{$Sandy}}", - KernelArguments.builder() - .withVariable("Sandy", sandy, typeConverter) - .build()) - .withTypeConverter(typeConverter) - .withResultType(Pet.class) - .block() - .getResult(); - - System.out.println("Sandy's updated record: " + updated); - } - - public static void exampleUsingGlobalTypes(ChatCompletionService chatCompletionService) { - Pet sandy = new Pet("Sandy", 3, "Dog"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - - // Create a converter that defaults to using jackson for serialization - ContextVariableTypeConverter typeConverter = ContextVariableJacksonConverter.create( - Pet.class); - - // Add converter to global types - ContextVariableTypes.addGlobalConverter(typeConverter); - - // No need to explicitly tell the invocation how to convert the type - Pet updated = kernel.invokePromptAsync( - "Sandy's is actually a cat correct this:\n{{$Sandy}}", - KernelArguments.builder() - .withVariable("Sandy", sandy) - .build()) - .withResultType(Pet.class) - .block() - .getResult(); - - System.out.println("Sandy's updated record: " + updated); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionTelemetry_Example.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionTelemetry_Example.java deleted file mode 100644 index 4ca35a80f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionTelemetry_Example.java +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.java; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example59_OpenAIFunctionCalling.PetPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.ServiceNotFoundException; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Scope; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; -import reactor.core.publisher.Mono; - -public class FunctionTelemetry_Example { - /* - * // Get the Application Insights agent from - * https://github.com/microsoft/ApplicationInsights-Java, e.g: - * ``` - * wget -O "/tmp/applicationinsights-agent-3.6.1.jar" - * "https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.6.1/applicationinsights-agent-3.6.1.jar" - * ``` - * - * // Get your application insights connection string from the Azure portal - * ``` - * CLIENT_ENDPOINT="" \ - * AZURE_CLIENT_KEY="" \ - * APPLICATIONINSIGHTS_CONNECTION_STRING="" \ - * MAVEN_OPTS="-javaagent:/tmp/applicationinsights-agent-3.6.1.jar" \ - * ../../../mvnw package exec:java -Dsample="java.FunctionTelemetry_Example" - * ``` - * - * If you open the Application Insights "Live metrics" view while running this example, you - * should see the telemetry in real-time. - * Otherwise within a few minutes, you should see the telemetry in the Application Insights -> - * Investigate -> Transaction search ui in the Azure portal. - */ - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = "gpt-4o"; - - public static void main(String[] args) - throws ConfigurationException, IOException, NoSuchMethodException, InterruptedException { - requestsWithSpanContext(); - testNestedCalls(); - requestsWithScope(); - - Thread.sleep(1000); - } - - private static void requestsWithSpanContext() throws IOException { - Span fakeRequest = GlobalOpenTelemetry.getTracer("Custom") - .spanBuilder("GET /requestsWithSpanContext") - .setSpanKind(SpanKind.SERVER) - .setAttribute("http.request.method", "GET") - .setAttribute("url.path", "/requestsWithSpanContext") - .setAttribute("url.scheme", "http") - .startSpan(); - - // Pass span context to the telemetry object to correlate telemetry with the request - SemanticKernelTelemetry telemetry = new SemanticKernelTelemetry( - GlobalOpenTelemetry.getTracer("Custom"), - fakeRequest.getSpanContext()); - - sequentialFunctionCalls(telemetry); - - fakeRequest.setStatus(StatusCode.OK); - fakeRequest.end(); - } - - private static void requestsWithScope() throws IOException { - Span fakeRequest = GlobalOpenTelemetry.getTracer("Custom") - .spanBuilder("GET /requestsWithScope") - .setSpanKind(SpanKind.SERVER) - .setAttribute("http.request.method", "GET") - .setAttribute("url.path", "/requestsWithScope") - .setAttribute("url.scheme", "http") - .startSpan(); - - // Pass span context to the telemetry object to correlate telemetry with the request - SemanticKernelTelemetry telemetry = new SemanticKernelTelemetry(); - - try (Scope scope = fakeRequest.makeCurrent()) { - sequentialFunctionCalls(telemetry); - } - - fakeRequest.setStatus(StatusCode.OK); - fakeRequest.end(); - } - - public static void sequentialFunctionCalls(SemanticKernelTelemetry telemetry) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var plugin = KernelPluginFactory.createFromObject(new PetPlugin(), "PetPlugin"); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin(plugin) - .build(); - - var chatHistory = new ChatHistory(); - chatHistory.addUserMessage( - "What is the name and type of the pet with id ca2fc6bc-1307-4da6-a009-d7bf88dec37b?"); - - var messages = chat.getChatMessageContentsAsync( - chatHistory, - kernel, - InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.FULL_HISTORY) - .withTelemetry(telemetry) - .build()) - .block(); - - chatHistory = new ChatHistory(messages); - - System.out.println( - "THE NAME AND TYPE IS: " + chatHistory.getLastMessage().get().getContent()); - } - - public static void testNestedCalls() { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var plugin = KernelPluginFactory.createFromObject(new TextAnalysisPlugin(), - "TextAnalysisPlugin"); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin(plugin) - .build(); - - SemanticKernelTelemetry telemetry = new SemanticKernelTelemetry(); - - Span span = GlobalOpenTelemetry.getTracer("Test") - .spanBuilder("testNestedCalls span") - .setSpanKind(SpanKind.SERVER) - .startSpan(); - - try (Scope scope = span.makeCurrent()) { - String analysed = kernel - .invokePromptAsync( - """ - Analyse the following text: - Hello There - """, - KernelArguments.builder().build(), - InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY) - .withTelemetry(telemetry) - .build()) - .withResultType(String.class) - .map(result -> { - return result.getResult(); - }) - .block(); - System.out.println(analysed); - } finally { - span.end(); - } - - } - - public static class TextAnalysisPlugin { - - @DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase") - public String uppercase( - @KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) { - return text.toUpperCase(Locale.ROOT); - } - - @DefineKernelFunction(name = "sha256sum", description = "Calculates a sha256 of the input", returnType = "string") - public Mono sha256sum( - @KernelFunctionParameter(name = "input", description = "The input to checksum", type = String.class) String input, - Kernel kernel, - SemanticKernelTelemetry telemetry) throws NoSuchAlgorithmException { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); - String hashStr = new BigInteger(1, hash).toString(16); - - return kernel - .invokePromptAsync( - """ - Uppercase the following text: - === BEGIN TEXT === - %s - === END TEXT === - """.formatted(hashStr) - .stripIndent(), - null, - InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY) - .withTelemetry(telemetry) - .build()) - .withResultType(String.class) - .map(result -> { - return result.getResult(); - }); - } - - @DefineKernelFunction(name = "formatAnswer", description = "Formats an answer", returnType = "string") - public Mono formatAnswer( - @KernelFunctionParameter(name = "input", description = "The input to format", type = String.class) String input, - Kernel kernel, - SemanticKernelTelemetry telemetry) throws ServiceNotFoundException { - - return kernel - .invokePromptAsync( - """ - Translate the following text into Italian: - === BEGIN TEXT === - %s - === END TEXT === - """.formatted(input) - .stripIndent()) - .withResultType(String.class) - .map(result -> { - return result.getResult(); - }); - } - - @DefineKernelFunction(name = "analyseInput", description = "Gives a text analysis of the input", returnType = "string") - public Mono analyseInput( - @KernelFunctionParameter(name = "input", description = "The input to analyse", type = String.class) String input, - Kernel kernel, - SemanticKernelTelemetry telemetry) throws ServiceNotFoundException { - - return kernel - .invokePromptAsync( - """ - Calculating sha256sum of the following text: - === BEGIN TEXT === - %s - === END TEXT === - """.formatted(input) - .stripIndent(), - null, - InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY) - .withTelemetry(telemetry) - .build()) - .withResultType(String.class) - .map(result -> { - return result.getResult(); - }) - .flatMap(answer -> { - return kernel - .invokePromptAsync( - """ - Format the following text: - === BEGIN TEXT === - %s - === END TEXT === - """.formatted(answer) - .stripIndent()) - .withInvocationContext( - InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .withReturnMode(InvocationReturnMode.NEW_MESSAGES_ONLY) - .withTelemetry(telemetry) - .build()) - .withArguments(null) - .withTelemetry(telemetry) - .withResultType(String.class); - }) - .map(it -> { - return it.getResult(); - }); - } - - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsHandlebars_Example.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsHandlebars_Example.java deleted file mode 100644 index 29ad37696..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsHandlebars_Example.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.java; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class FunctionsHandlebars_Example { - - public static void main(String[] args) throws ConfigurationException, IOException { - - Kernel kernel = Kernel.builder() - .withPlugin( - KernelPluginFactory.createFromObject( - new StringHelper(), "StringHelper")) - .build(); - - List choices = Arrays.asList("ContinueConversation", "EndConversation"); - - var promptTemplate = new KernelPromptTemplateFactory() - .tryCreate(PromptTemplateConfig - .builder() - .withTemplate( - """ - Choices: {{choices}}. - Screaming Snake Case: {{StringHelper-toScreamingSnakeCase (StringHelper-toListString [choices])}} - """) - .withTemplateFormat("handlebars") - .build()); - - var renderedPrompt = promptTemplate.renderAsync( - kernel, - KernelArguments.builder() - .withVariable("choices", choices) - .build(), - null) - .block(); - System.out.println(renderedPrompt); - - } - - public static class StringHelper { - - @DefineKernelFunction(name = "toScreamingSnakeCase", description = "Converts a string to screaming snake case") - public static String toScreamingSnakeCase( - @KernelFunctionParameter(name = "in", description = "The string to screaming snake") String in) { - Pattern p = Pattern.compile("([^,])([A-Z])([^A-Z]+)"); - Matcher m = p.matcher(in); - StringBuilder s = new StringBuilder(); - while (m.find()) { - m.appendReplacement(s, m.group(1) + "_" + m.group(2) + m.group(3)); - } - return s.toString().toUpperCase(Locale.ROOT); - } - - @DefineKernelFunction(name = "toListString", description = "Converts a string to a list") - public static String toListString( - @KernelFunctionParameter(name = "in", description = "The string to convert to a list", type = java.util.List.class) List in) { - return String.join(",", in); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsWithinPrompts_Example.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsWithinPrompts_Example.java deleted file mode 100644 index 7e92e3e6e..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/FunctionsWithinPrompts_Example.java +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.java; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; -import java.util.stream.Collectors; - -public class FunctionsWithinPrompts_Example { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo-2"); - - public static InputStream INPUT = System.in; - - public static void main(String[] args) throws ConfigurationException, IOException { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), "ConversationSummaryPlugin"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin(plugin) - .build(); - - List choices = Arrays.asList("ContinueConversation", "EndConversation"); - - // Create few-shot examples - List fewShotExamples = Arrays.asList( - new ChatHistory( - Arrays.asList( - ChatMessageTextContent.userMessage( - "Can you send a very quick approval to the marketing team?"), - ChatMessageTextContent.systemMessage("Intent:"), - ChatMessageTextContent.assistantMessage("ContinueConversation"))), - - new ChatHistory( - Arrays.asList( - ChatMessageTextContent.userMessage("Thats all"), - ChatMessageTextContent.systemMessage("Intent:"), - ChatMessageTextContent.assistantMessage("EndConversation")))); - - // Create handlebars template for intent - // - var getIntent = KernelFunctionFromPrompt - .createFromPrompt( - """ - Instructions: What is the intent of this request? - Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}. - Choices: {{choices}}. - - {{#each fewShotExamples}} - {{#each this}} - {{content}} - {{/each}} - {{/each}} - - {{request}} - Intent:""" - .stripIndent()) - .withTemplateFormat("handlebars") - .build(); - // - - // Create a Semantic Kernel template for chat - // - var chat = KernelFunctionFromPrompt.createFromPrompt(""" - Answer the users question below taking into account the conversation so far. - - [START SUMMARY OF CONVERSATION SO FAR] - {{ConversationSummaryPlugin.SummarizeConversation $history}} - [END SUMMARY OF CONVERSATION SO FAR] - - User: {{$request}} - Assistant: - """.stripIndent()).build(); - // - - Scanner scanner = new Scanner(INPUT); - - ChatHistory history = new ChatHistory(); - // Start the chat loop - while (true) { - // Get user input - System.out.println("User > "); - var request = scanner.nextLine(); - - String historyString = history.getMessages() - .stream() - .map(message -> message.getAuthorRole() + ": " + message.getContent()) - .collect(Collectors.joining("\n")); - - /* - * Renders to: - * - * Instructions: What is the intent of this request? - * Do not explain the reasoning, just reply back with the intent. If you are unsure, - * reply with . - * Choices: ContinueConversation,EndConversation. - * - * Can you send a very quick approval to the marketing - * team? - * Intent: - * ContinueConversation - * Can you send the full update to the marketing team? - * Intent: - * EndConversation - * - * Can you send an approval to the marketing team? - * Intent: - */ - - // Invoke handlebars prompt - var intent = kernel.invokeAsync(getIntent) - .withArguments( - KernelArguments.builder() - .withVariable("request", request) - .withVariable("choices", choices) - .withVariable("history", historyString) - .withVariable("fewShotExamples", fewShotExamples) - .build()) - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(true, - plugin.get("SummarizeConversation"))) - .block(); - - // End the chat if the intent is "Stop" - if ("EndConversation".equalsIgnoreCase(intent.getResult())) { - break; - } - - // Get chat response - var chatResult = kernel.invokeAsync(chat) - .withArguments( - KernelArguments.builder() - .withVariable("request", request) - .withVariable("history", historyString) - .build()) - .block(); - - String message = chatResult.getResult(); - System.out.println("Assistant: " + message); - System.out.println(); - - // Append to history - history.addUserMessage(request); - history.addAssistantMessage(message); - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/KernelFunctionYaml_Example.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/KernelFunctionYaml_Example.java deleted file mode 100644 index 10e9a014e..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/java/KernelFunctionYaml_Example.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.java; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.Kernel.Builder; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionYaml; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.io.IOException; -import javax.annotation.Nullable; - -public class KernelFunctionYaml_Example { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws ConfigurationException, IOException { - run(null); - } - - public static void run(@Nullable SemanticKernelTelemetry telemetry) throws IOException { - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Builder kernelBuilder = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion); - - semanticKernelTemplate(kernelBuilder.build(), telemetry); - handlebarsTemplate(kernelBuilder.build(), telemetry); - } - - private static void handlebarsTemplate(Kernel kernel, - @Nullable SemanticKernelTelemetry telemetry) - throws IOException { - String yaml = EmbeddedResourceLoader.readFile("GenerateStoryHandlebars.yaml", - KernelFunctionYaml_Example.class); - - KernelFunction function = KernelFunctionYaml.fromPromptYaml(yaml); - - FunctionResult result = function - .invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withVariable("length", 5) - .withVariable("topic", "dogs") - .build()) - .withTelemetry(telemetry) - .block(); - - System.out.println(result.getResult()); - } - - private static void semanticKernelTemplate(Kernel kernel, - @Nullable SemanticKernelTelemetry telemetry) - throws IOException { - String yaml = EmbeddedResourceLoader.readFile("GenerateStory.yaml", - KernelFunctionYaml_Example.class); - - KernelFunction function = KernelFunctionYaml.fromPromptYaml(yaml); - - FunctionResult result = function - .invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withVariable("length", 5) - .withVariable("topic", "cats") - .build()) - .withTelemetry(telemetry) - .block(); - - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/InMemoryVolatileVectorStore.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/InMemoryVolatileVectorStore.java deleted file mode 100644 index ef4fe9549..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/InMemoryVolatileVectorStore.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.memory; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.textembedding.OpenAITextEmbeddingGenerationService; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.VolatileVectorStore; -import com.microsoft.semantickernel.data.VolatileVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class InMemoryVolatileVectorStore { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - // Embedding model configuration - private static final String MODEL_ID = System.getenv() - .getOrDefault("EMBEDDING_MODEL_ID", "text-embedding-3-large"); - private static final int EMBEDDING_DIMENSIONS = 1536; - - static class GitHubFile { - @VectorStoreRecordKey - private final String id; - @VectorStoreRecordData - private final String description; - @VectorStoreRecordData - private final String link; - @VectorStoreRecordVector(dimensions = EMBEDDING_DIMENSIONS, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private final List embedding; - - public GitHubFile( - String id, - String description, - String link, - List embedding) { - this.id = id; - this.description = description; - this.link = link; - this.embedding = embedding; - } - - public String getId() { - return id; - } - - public String getDescription() { - return description; - } - - public String getLink() { - return link; - } - - public List getEmbedding() { - return embedding; - } - - static String encodeId(String realId) { - return VectorStoreWithAzureAISearch.GitHubFile.encodeId(realId); - } - } - - public static void main(String[] args) { - System.out.println("==================================================================="); - System.out.println("========== Volatile (In memory) Vector Store Example =============="); - System.out.println("==================================================================="); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - var embeddingGeneration = OpenAITextEmbeddingGenerationService.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .withDimensions(EMBEDDING_DIMENSIONS) - .build(); - - inMemoryStoreAndSearch(embeddingGeneration); - } - - public static void inMemoryStoreAndSearch( - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Create a new Volatile vector store - var volatileVectorStore = new VolatileVectorStore(); - - String collectionName = "skgithubfiles"; - var collection = volatileVectorStore.getCollection(collectionName, - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(GitHubFile.class) - .build()); - - // Create collection if it does not exist and store data - collection - .createCollectionIfNotExistsAsync() - .then(storeData(collection, embeddingGeneration, sampleData())) - .block(); - - // Search for results - // Volatile store executes an exhaustive search, for approximate search use Azure AI Search, Redis or JDBC with PostgreSQL - var results = search("How to get started", collection, embeddingGeneration).block(); - - if (results == null || results.getTotalCount() == 0) { - System.out.println("No search results found."); - return; - } - var searchResult = results.getResults().get(0); - System.out.printf("Search result with score: %f.%n Link: %s, Description: %s%n", - searchResult.getScore(), searchResult.getRecord().link, - searchResult.getRecord().description); - } - - private static Mono> search( - String searchText, - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Generate embeddings for the search text and search for the closest records - return embeddingGeneration.generateEmbeddingAsync(searchText) - .flatMap(r -> recordCollection.searchAsync(r.getVector(), null)); - } - - private static Mono> storeData( - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration, - Map data) { - - return Flux.fromIterable(data.entrySet()) - .flatMap(entry -> { - System.out.println("Save '" + entry.getKey() + "' to memory."); - - // Generate embeddings for the data and store it - return embeddingGeneration - .generateEmbeddingsAsync(Collections.singletonList(entry.getValue())) - .flatMap(embeddings -> { - GitHubFile gitHubFile = new GitHubFile( - GitHubFile.encodeId(entry.getKey()), - entry.getValue(), - entry.getKey(), - embeddings.get(0).getVector()); - return recordCollection.upsertAsync(gitHubFile, null); - }); - }) - .collectList(); - } - - private static Map sampleData() { - return Arrays.stream(new String[][] { - { "https://github.com/microsoft/semantic-kernel/blob/main/README.md", - "README: Installation, getting started with Semantic Kernel, and how to contribute" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", - "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function" }, - { "https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", - "Sample demonstrating how to create a chat skill interfacing with ChatGPT" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", - "C# class that defines a volatile embedding store" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", - "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", - "README: README associated with a sample chat summary react-based webapp" }, - }).collect(Collectors.toMap(element -> element[0], element -> element[1])); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithAzureAISearch.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithAzureAISearch.java deleted file mode 100644 index 382bf0f83..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithAzureAISearch.java +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.memory; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.azure.core.util.ClientOptions; -import com.azure.core.util.MetricsOptions; -import com.azure.core.util.TracingOptions; -import com.azure.search.documents.indexes.SearchIndexAsyncClient; -import com.azure.search.documents.indexes.SearchIndexClientBuilder; -import com.microsoft.semantickernel.aiservices.openai.textembedding.OpenAITextEmbeddingGenerationService; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStore; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStoreOptions; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class VectorStoreWithAzureAISearch { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - ////////////////////////////////////////////////////////////// - // Azure AI Search configuration - ////////////////////////////////////////////////////////////// - private static final String AZURE_AI_SEARCH_ENDPOINT = System.getenv("AZURE_AISEARCH_ENDPOINT"); - private static final String AZURE_AISEARCH_KEY = System.getenv("AZURE_AISEARCH_KEY"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("EMBEDDING_MODEL_ID", "text-embedding-3-large"); - private static final int EMBEDDING_DIMENSIONS = 1536; - - static class GitHubFile { - @VectorStoreRecordKey - private final String id; - @VectorStoreRecordData - private final String description; - @VectorStoreRecordData - private final String link; - @VectorStoreRecordVector(dimensions = EMBEDDING_DIMENSIONS, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_SIMILARITY) - private final List embedding; - - public GitHubFile() { - this(null, null, null, Collections.emptyList()); - } - - public GitHubFile( - String id, - String description, - String link, - List embedding) { - this.id = id; - this.description = description; - this.link = link; - this.embedding = embedding; - } - - static String encodeId(String realId) { - byte[] bytes = Base64.getUrlEncoder().encode(realId.getBytes(StandardCharsets.UTF_8)); - return new String(bytes, StandardCharsets.UTF_8); - } - } - - public static void main(String[] args) { - System.out.println("=============================================================="); - System.out.println("========== Azure AI Search Vector Store Example =============="); - System.out.println("=============================================================="); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - var embeddingGeneration = OpenAITextEmbeddingGenerationService.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .withDimensions(EMBEDDING_DIMENSIONS) - .build(); - - var searchClient = new SearchIndexClientBuilder() - .endpoint(AZURE_AI_SEARCH_ENDPOINT) - .credential(new AzureKeyCredential(AZURE_AISEARCH_KEY)) - .clientOptions(clientOptions()) - .buildAsyncClient(); - - storeAndSearch(searchClient, embeddingGeneration); - } - - public static void storeAndSearch( - SearchIndexAsyncClient searchClient, - OpenAITextEmbeddingGenerationService embeddingGeneration) { - - // Build an Azure AI Search Vector Store - var azureAISearchVectorStore = AzureAISearchVectorStore.builder() - .withSearchIndexAsyncClient(searchClient) - .withOptions(new AzureAISearchVectorStoreOptions()) - .build(); - - String collectionName = "skgithubfiles"; - var collection = azureAISearchVectorStore - .getCollection( - collectionName, - AzureAISearchVectorStoreRecordCollectionOptions.builder() - .withRecordClass(GitHubFile.class) - .build()); - - // Create collection if it does not exist and store data - collection - .createCollectionIfNotExistsAsync() - .then(storeData(collection, embeddingGeneration, sampleData())) - .block(); - - // Search for results - // Might need to wait for the data to be indexed - var results = search("How to get started", collection, embeddingGeneration).block(); - - if (results == null || results.getTotalCount() == 0) { - System.out.println("No search results found."); - return; - } - var searchResult = results.getResults().get(0); - System.out.printf("Search result with score: %f.%n Link: %s, Description: %s%n", - searchResult.getScore(), searchResult.getRecord().link, - searchResult.getRecord().description); - } - - private static Mono> search( - String searchText, - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Generate embeddings for the search text and search for the closest records - return embeddingGeneration.generateEmbeddingAsync(searchText) - .flatMap(r -> recordCollection.searchAsync(r.getVector(), null)); - } - - private static Mono> storeData( - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration, - Map data) { - - return Flux.fromIterable(data.entrySet()) - .flatMap(entry -> { - System.out.println("Save '" + entry.getKey() + "' to memory."); - - // Generate embeddings for the data and store it - return embeddingGeneration - .generateEmbeddingsAsync(Collections.singletonList(entry.getValue())) - .flatMap(embeddings -> { - GitHubFile gitHubFile = new GitHubFile( - GitHubFile.encodeId(entry.getKey()), - entry.getValue(), - entry.getKey(), - embeddings.get(0).getVector()); - return recordCollection.upsertAsync(gitHubFile, null); - }); - }) - .collectList(); - } - - private static Map sampleData() { - return Arrays.stream(new String[][] { - { "https://github.com/microsoft/semantic-kernel/blob/main/README.md", - "README: Installation, getting started with Semantic Kernel, and how to contribute" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", - "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function" }, - { "https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", - "Sample demonstrating how to create a chat skill interfacing with ChatGPT" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", - "C# class that defines a volatile embedding store" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", - "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", - "README: README associated with a sample chat summary react-based webapp" }, - }).collect(Collectors.toMap(element -> element[0], element -> element[1])); - } - - private static ClientOptions clientOptions() { - return new ClientOptions() - .setTracingOptions(new TracingOptions()) - .setMetricsOptions(new MetricsOptions()) - .setApplicationId("Semantic-Kernel"); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithJDBC.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithJDBC.java deleted file mode 100644 index b9ff7aa91..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithJDBC.java +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.memory; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.textembedding.OpenAITextEmbeddingGenerationService; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; - -import java.nio.charset.StandardCharsets; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.postgresql.ds.PGSimpleDataSource; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class VectorStoreWithJDBC { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("EMBEDDING_MODEL_ID", "text-embedding-3-large"); - private static final int EMBEDDING_DIMENSIONS = 1536; - - static class GitHubFile { - @VectorStoreRecordKey - private final String id; - @VectorStoreRecordData - private final String description; - @VectorStoreRecordData - private final String link; - @VectorStoreRecordVector(dimensions = EMBEDDING_DIMENSIONS, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private final List embedding; - - public GitHubFile() { - this(null, null, null, Collections.emptyList()); - } - - public GitHubFile( - String id, - String description, - String link, - List embedding) { - this.id = id; - this.description = description; - this.link = link; - this.embedding = embedding; - } - - public String getId() { - return id; - } - - public String getDescription() { - return description; - } - - public String getLink() { - return link; - } - - public List getEmbedding() { - return embedding; - } - - static String encodeId(String realId) { - byte[] bytes = Base64.getUrlEncoder().encode(realId.getBytes(StandardCharsets.UTF_8)); - return new String(bytes, StandardCharsets.UTF_8); - } - } - - // Run a PostgreSQL server with: - // docker run -d --name pgvector-container -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=root -e POSTGRES_DB=sk -p 5432:5432 pgvector/pgvector:pg17 - - public static void main(String[] args) throws SQLException { - System.out.println("=============================================================="); - System.out.println("=============== JDBC Vector Store Example ===================="); - System.out.println("=============================================================="); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // Create an OpenAI text embedding generation service - var embeddingGeneration = OpenAITextEmbeddingGenerationService.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .withDimensions(EMBEDDING_DIMENSIONS) - .build(); - - storeAndSearch(embeddingGeneration); - } - - public static void storeAndSearch(OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Configure the data source - PGSimpleDataSource dataSource = new PGSimpleDataSource(); - dataSource.setUrl("jdbc:postgresql://localhost:5432/sk"); - dataSource.setUser("postgres"); - dataSource.setPassword("root"); - - // Build a query provider - // Other available query providers are PostgreSQLVectorStoreQueryProvider and SQLiteVectorStoreQueryProvider - var queryProvider = PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - - // Build a vector store - var jdbcVectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - // Set up the record collection to use - String collectionName = "skgithubfiles"; - var collection = jdbcVectorStore.getCollection(collectionName, - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(GitHubFile.class) - .build()); - - // Create collection if it does not exist and store data - collection - .createCollectionIfNotExistsAsync() - .then(storeData(collection, embeddingGeneration, sampleData())) - .block(); - - // Search for results - var results = search("How to get started", collection, embeddingGeneration).block(); - - if (results == null || results.getTotalCount() == 0) { - System.out.println("No search results found."); - return; - } - var searchResult = results.getResults().get(0); - System.out.printf("Search result with score: %f.%n Link: %s, Description: %s%n", - searchResult.getScore(), searchResult.getRecord().link, - searchResult.getRecord().description); - } - - private static Mono> search( - String searchText, - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Generate embeddings for the search text and search for the closest records - return embeddingGeneration.generateEmbeddingAsync(searchText) - .flatMap(r -> recordCollection.searchAsync(r.getVector(), null)); - } - - private static Mono> storeData( - VectorStoreRecordCollection recordStore, - OpenAITextEmbeddingGenerationService embeddingGeneration, - Map data) { - - return Flux.fromIterable(data.entrySet()) - .flatMap(entry -> { - System.out.println("Save '" + entry.getKey() + "' to memory."); - - // Generate embeddings for the data and store it - return embeddingGeneration - .generateEmbeddingsAsync(Collections.singletonList(entry.getValue())) - .flatMap(embeddings -> { - GitHubFile gitHubFile = new GitHubFile( - GitHubFile.encodeId(entry.getKey()), - entry.getValue(), - entry.getKey(), - embeddings.get(0).getVector()); - return recordStore.upsertAsync(gitHubFile, null); - }); - }) - .collectList(); - } - - private static Map sampleData() { - return Arrays.stream(new String[][] { - { "https://github.com/microsoft/semantic-kernel/blob/main/README.md", - "README: Installation, getting started with Semantic Kernel, and how to contribute" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", - "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function" }, - { "https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", - "Sample demonstrating how to create a chat skill interfacing with ChatGPT" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", - "C# class that defines a volatile embedding store" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", - "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", - "README: README associated with a sample chat summary react-based webapp" }, - }).collect(Collectors.toMap(element -> element[0], element -> element[1])); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithOracle.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithOracle.java deleted file mode 100644 index e32131050..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithOracle.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.memory; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.oracle.OracleVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; -import java.sql.SQLException; -import java.util.Collections; -import oracle.jdbc.datasource.impl.OracleDataSource; - -public class VectorStoreWithOracle { - - public static void main(String[] args) throws SQLException { - System.out.println("=============================================================="); - System.out.println("============== Oracle Vector Store Example ==================="); - System.out.println("=============================================================="); - - // Configure the data source - OracleDataSource dataSource = new OracleDataSource(); - dataSource.setURL("jdbc:oracle:thin:@localhost:1521/FREEPDB1"); - dataSource.setUser("scott"); - dataSource.setPassword("tiger"); - - // Build a query provider - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - - // Build a vector store - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - // Get a collection from the vector store - VectorStoreRecordCollection collection = vectorStore.getCollection( - "skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - // Create the collection if it doesn't exist yet. - collection.createCollectionAsync().block(); - - collection.upsertAsync(new Hotel("1", - "HotelOne", - "Desc for HotelOne", - Collections.emptyList(), Collections.emptyList()), - null) - .block(); - - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithRedis.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithRedis.java deleted file mode 100644 index b6bebff81..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/memory/VectorStoreWithRedis.java +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.memory; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.textembedding.OpenAITextEmbeddingGenerationService; -import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.redis.RedisStorageType; -import com.microsoft.semantickernel.data.redis.RedisVectorStore; -import com.microsoft.semantickernel.data.redis.RedisVectorStoreOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import redis.clients.jedis.JedisPooled; - -public class VectorStoreWithRedis { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("EMBEDDING_MODEL_ID", "text-embedding-3-large"); - private static final int EMBEDDING_DIMENSIONS = 1536; - - public static class GitHubFile { - @VectorStoreRecordKey - private final String id; - @VectorStoreRecordData - private final String description; - @VectorStoreRecordData - private final String link; - @VectorStoreRecordVector(dimensions = EMBEDDING_DIMENSIONS, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private final List embedding; - - public GitHubFile() { - this(null, null, null, Collections.emptyList()); - } - - public GitHubFile( - String id, - String description, - String link, - List embedding) { - this.id = id; - this.description = description; - this.link = link; - this.embedding = embedding; - } - - public String getId() { - return id; - } - - public String getDescription() { - return description; - } - - public String getLink() { - return link; - } - - public List getEmbedding() { - return embedding; - } - - static String encodeId(String realId) { - return VectorStoreWithAzureAISearch.GitHubFile.encodeId(realId); - } - } - - // Can start a test server with: - // docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest - private static final String REDIS_URL = "redis://127.0.0.1:6379"; - - public static void main(String[] args) { - System.out.println("=============================================================="); - System.out.println("================ Redis Vector Store Example =================="); - System.out.println("=============================================================="); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - var embeddingGeneration = OpenAITextEmbeddingGenerationService.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .withDimensions(EMBEDDING_DIMENSIONS) - .build(); - - storeAndSearch(embeddingGeneration); - } - - public static void storeAndSearch( - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Configure redis client - JedisPooled jedis = new JedisPooled(REDIS_URL); - - // Build a vector store - // Available storage types are JSON and HASHSET. Default is JSON. - var vectorStore = RedisVectorStore.builder() - .withClient(jedis) - .withOptions( - RedisVectorStoreOptions.builder().withStorageType(RedisStorageType.JSON).build()) - .build(); - - // Set up the record collection to use - String collectionName = "skgithubfiles"; - var collection = vectorStore.getCollection(collectionName, - RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(GitHubFile.class) - .build()); - - // Create collection if it does not exist and store data - collection - .createCollectionIfNotExistsAsync() - .then(storeData(collection, embeddingGeneration, sampleData())) - .block(); - - // Search for results - // Might need to wait for the data to be indexed - var results = search("How to get started", collection, embeddingGeneration).block(); - - if (results == null || results.getTotalCount() == 0) { - System.out.println("No search results found."); - return; - } - var searchResult = results.getResults().get(0); - System.out.printf("Search result with score: %f.%n Link: %s, Description: %s%n", - searchResult.getScore(), searchResult.getRecord().link, - searchResult.getRecord().description); - } - - private static Mono> search( - String searchText, - VectorStoreRecordCollection recordCollection, - OpenAITextEmbeddingGenerationService embeddingGeneration) { - // Generate embeddings for the search text and search for the closest records - return embeddingGeneration.generateEmbeddingAsync(searchText) - .flatMap(r -> recordCollection.searchAsync(r.getVector(), null)); - } - - private static Mono> storeData( - VectorStoreRecordCollection recordStore, - OpenAITextEmbeddingGenerationService embeddingGeneration, - Map data) { - - return Flux.fromIterable(data.entrySet()) - .flatMap(entry -> { - System.out.println("Save '" + entry.getKey() + "' to memory."); - - // Generate embeddings for the data and store it - return embeddingGeneration - .generateEmbeddingsAsync(Collections.singletonList(entry.getValue())) - .flatMap(embeddings -> { - GitHubFile gitHubFile = new GitHubFile( - GitHubFile.encodeId(entry.getKey()), - entry.getValue(), - entry.getKey(), - embeddings.get(0).getVector()); - return recordStore.upsertAsync(gitHubFile, null); - }); - }) - .collectList(); - } - - private static Map sampleData() { - return Arrays.stream(new String[][] { - { "https://github.com/microsoft/semantic-kernel/blob/main/README.md", - "README: Installation, getting started with Semantic Kernel, and how to contribute" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", - "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function" }, - { "https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", - "Sample demonstrating how to create a chat skill interfacing with ChatGPT" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", - "C# class that defines a volatile embedding store" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", - "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4" }, - { "https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", - "README: README associated with a sample chat summary react-based webapp" }, - }).collect(Collectors.toMap(element -> element[0], element -> element[1])); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example07_BingAndGooglePlugins.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example07_BingAndGooglePlugins.java deleted file mode 100644 index 2e4462fd2..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example07_BingAndGooglePlugins.java +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.plugin; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.samples.connectors.web.bing.BingConnector; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.web.WebSearchEnginePlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -/// -/// The example shows how to use Bing and Google to search for current data -/// you might want to import into your system, e.g. providing AI prompts with -/// recent information, or for AI to generate recent information to display to users. -/// -public class Example07_BingAndGooglePlugins { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - private static final String BING_API_KEY = System.getenv("BING_API_KEY"); - private static final String GOOGLE_API_KEY = System.getenv("GOOGLE_API_KEY"); - private static final String GOOGLE_SEARCH_ENGINE_ID = System.getenv("GOOGLE_SEARCH_ENGINE_ID"); - - public static void main(String[] args) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // Load Bing plugin - var bingConnector = new BingConnector(BING_API_KEY); - var bing = KernelPluginFactory.createFromObject(new WebSearchEnginePlugin(bingConnector), - "bing"); - - var chatCompletionService = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - var kernel = Kernel.builder() - .withPlugin(bing) - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - - example1Async(kernel, "bing"); - example2Async(kernel); - - // Load Google plugin - // WebSearchEngineConnector googleConnector = new GoogleConnector(GOOGLE_API_KEY, GOOGLE_SEARCH_ENGINE_ID); - // WebSearchEnginePlugin bing = new WebSearchEnginePlugin(googleConnector); - // kernel.importPluginFromObject(new WebSearchEnginePlugin(googleConnector), "google"); - } - - private static void example1Async(Kernel kernel, String searchPluginName) { - System.out.println("======== Bing and Google Search Plugins ========"); - - // Run - var question = "What's the largest building in the world?"; - var kernelArguments = KernelArguments.builder() - .withVariable("query", question) - .build(); - - var function = kernel.getFunction(searchPluginName, "search"); - var result = kernel.invokeAsync(function).withArguments(kernelArguments).block(); - - System.out.println(question); - System.out.printf("----%s----%n", searchPluginName); - System.out.println(result.getResult()); - - /* - * OUTPUT: - * - * What's the largest building in the world? - * ---- - * The Aerium near Berlin, Germany is the largest uninterrupted volume in the world, while - * Boeing's - * factory in Everett, Washington, United States is the world's largest building by volume. - * The AvtoVAZ - * main assembly building in Tolyatti, Russia is the largest building in area footprint. - * ---- - * The Aerium near Berlin, Germany is the largest uninterrupted volume in the world, while - * Boeing's - * factory in Everett, Washington, United States is the world's ... - */ - } - - private static void example2Async(Kernel kernel) { - System.out.println("======== Use Search Plugin to answer user questions ========"); - - var semanticFunction = """ - Answer questions only when you know the facts or the information is provided. - When you don't have sufficient information you reply with a list of commands to find the information needed. - When answering multiple questions, use a bullet point list. - Note: make sure single and double quotes are escaped using a backslash char. - - [COMMANDS AVAILABLE] - - bing.search - - [INFORMATION PROVIDED] - {{ $externalInformation }} - - [EXAMPLE 1] - Question: what's the biggest lake in Italy? - Answer: Lake Garda, also known as Lago di Garda. - - [EXAMPLE 2] - Question: what's the biggest lake in Italy? What's the smallest positive number? - Answer: - * Lake Garda, also known as Lago di Garda. - * The smallest positive number is 1. - - [EXAMPLE 3] - Question: what's Ferrari stock price? Who is the current number one female tennis player in the world? - Answer: - {{ '{{' }} bing.search "what's Ferrari stock price?" {{ '}}' }}. - {{ '{{' }} bing.search "Who is the current number one female tennis player in the world?" {{ '}}' }}. - - [END OF EXAMPLES] - - [TASK] - Question: {{ $question }}. - Answer: - """ - .stripIndent(); - - // The prompt function will append the answer here - var question = "Who is the most followed person on TikTok right now? What's the exchange rate EUR:USD?"; - System.out.println(question); - - var promptExecutionSettings = PromptExecutionSettings.builder() - .withMaxTokens(150) - .withTemperature(0) - .withTopP(1) - .build(); - - KernelFunction oracle = KernelFunctionFromPrompt.builder() - .withTemplate(semanticFunction) - .withDefaultExecutionSettings(promptExecutionSettings) - .build(); - - var kernelArguments = KernelArguments.builder() - .withVariable("question", question) - .withVariable("externalInformation", "") - .build(); - - FunctionResult answer = kernel.invokeAsync(oracle).withArguments(kernelArguments) - .block(); - - var result = answer.getResult(); - - // If the answer contains commands, execute them using the prompt renderer. - if (result.contains("bing.search")) { - PromptTemplate promptTemplate = new KernelPromptTemplateFactory() - .tryCreate(PromptTemplateConfig.builder().withTemplate(result).build()); - - System.out.println("---- Fetching information from Bing..."); - var information = promptTemplate.renderAsync(kernel, null, null).block(); - - System.out.println("Information found:"); - System.out.println(information); - - kernelArguments = KernelArguments.builder() - .withVariable("question", question) - .withVariable("externalInformation", information) - .build(); - - // Run the prompt function again, now including information from Bing - answer = kernel.invokeAsync(oracle).withArguments(kernelArguments).block(); - } else { - System.out.println("AI had all the information, no need to query Bing."); - } - - System.out.println("---- ANSWER:"); - System.out.println(answer.getResult()); - - /* - * OUTPUT: - * - * Who is the most followed person on TikTok right now? What's the exchange rate EUR:USD? - * ---- Fetching information from Bing... - * Information found: - * - * Khaby Lame is the most-followed user on TikTok. This list contains the top 50 accounts by - * number - * of followers on the Chinese social media platform TikTok, which was merged with - * musical.ly in 2018. - * [1] The most-followed individual on the platform is Khaby Lame, with over 153 million - * followers.. - * EUR – Euro To USD – US Dollar 1.00 Euro = 1.10 37097 US Dollars 1 USD = 0.906035 EUR We - * use the - * mid-market rate for our Converter. This is for informational purposes only. You won’t - * receive this - * rate when sending money. Check send rates Convert Euro to US Dollar Convert US Dollar to - * Euro.. - * ---- ANSWER: - * - * The most followed person on TikTok right now is Khaby Lame, with over 153 million - * followers. - * The exchange rate for EUR to USD is 1.1037097 US Dollars for 1 Euro. - */ - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example10_DescribeAllPluginsAndFunctions.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example10_DescribeAllPluginsAndFunctions.java deleted file mode 100644 index 7e4969d4a..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example10_DescribeAllPluginsAndFunctions.java +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.plugin; - -import java.nio.file.Path; -import java.util.Locale; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.Kernel.Builder; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.text.TextPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example10_DescribeAllPluginsAndFunctions { - - private static final String PLUGIN_DIR = System.getenv("PLUGIN_DIR") == null ? "." - : System.getenv("PLUGIN_DIR"); - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - /// - /// Print a list of all the functions imported into the kernel, including function descriptions, - /// list of parameters, parameters descriptions, etc. - /// See the end of the file for a sample of what the output looks like. - /// - public static void main(String[] args) { - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Builder kernelBuilder = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion); - - kernelBuilder.withPlugin( - KernelPluginFactory.createFromObject( - new StaticTextPlugin(), "StaticTextPlugin")); - - // Import another native plugin - kernelBuilder.withPlugin( - KernelPluginFactory.createFromObject( - new TextPlugin(), "AnotherTextPlugin")); - - kernelBuilder.withPlugin( - KernelPluginFactory - .importPluginFromDirectory( - Path.of(PLUGIN_DIR, - "samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins"), - "SummarizePlugin", - null)); - - // Not added to kernel so should not be printed - var jokeFunction = KernelFunctionFromPrompt.builder() - .withTemplate("tell a joke about {{$input}}") - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(150) - .build()) - .build(); - - // Not added to kernel so should not be printed - var writeNovel = KernelFunctionFromPrompt.builder() - .withTemplate("write a novel about {{$input}} in {{$language}} language") - .withName("Novel") - .withDescription("Write a bedtime story") - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(150) - .build()) - .build(); - - System.out.println("**********************************************"); - System.out.println("****** Registered plugins and functions ******"); - System.out.println("**********************************************"); - System.out.println(); - - Kernel kernel = kernelBuilder.build(); - kernel.getPlugins() - .forEach(plugin -> { - System.out.println("Plugin: " + plugin.getName()); - plugin - .getFunctions() - .values() - .stream() - .map(KernelFunction::getMetadata) - .forEach(Example10_DescribeAllPluginsAndFunctions::printFunction); - }); - } - - private static void printFunction(KernelFunctionMetadata func) { - System.out.println(" " + func.getName() + ": " + func.getDescription()); - - if (!func.getParameters().isEmpty()) { - System.out.println(" Params:"); - - func.getParameters() - .forEach(p -> { - System.out.println(" - " + p.getName() + ": " + p.getDescription()); - System.out.println(" default: '" + p.getDefaultValue() + "'"); - }); - } - - System.out.println(); - } - - public static class StaticTextPlugin { - - @DefineKernelFunction(description = "Change all string chars to uppercase", name = "uppercase") - public static String uppercase( - @KernelFunctionParameter(description = "Text to uppercase", name = "input") String input) { - return input.toUpperCase(Locale.ROOT); - } - - @DefineKernelFunction(description = "Append the day variable", name = "appendDay") - public String appendDay( - @KernelFunctionParameter(description = "Append the day variable", name = "appendDay") String input, - @KernelFunctionParameter(description = "Value of the day to append", name = "day") String day) { - return input + day; - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java deleted file mode 100644 index 47f0e5a46..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.plugin; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments.Builder; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import reactor.core.publisher.Mono; - -/** - * Demonstrate the {@see com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin} - * plugin. - *

- * Refer to the - * README for configuring your environment to run the examples. - */ -public class Example13_ConversationSummaryPlugin { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - private static final String chatTranscript = """ - John: Hello, how are you? - Jane: I'm fine, thanks. How are you? - John: I'm doing well, writing some example code. - Jane: That's great! I'm writing some example code too. - John: What are you writing? - Jane: I'm writing a chatbot. - John: That's cool. I'm writing a chatbot too. - Jane: What language are you writing it in? - John: I'm writing it in C#. - Jane: I'm writing it in Python. - John: That's cool. I need to learn Python. - Jane: I need to learn C#. - John: Can I try out your chatbot? - Jane: Sure, here's the link. - John: Thanks! - Jane: You're welcome. - Jane: Look at this poem my chatbot wrote: - Jane: Roses are red - Jane: Violets are blue - Jane: I'm writing a chatbot - Jane: What about you? - John: That's cool. Let me see if mine will write a poem, too. - John: Here's a poem my chatbot wrote: - John: The singularity of the universe is a mystery. - John: The universe is a mystery. - John: The universe is a mystery. - John: The universe is a mystery. - John: Looks like I need to improve mine, oh well. - Jane: You might want to try using a different model. - Jane: I'm using the GPT-3 model. - John: I'm using the GPT-2 model. That makes sense. - John: Here is a new poem after updating the model. - John: The universe is a mystery. - John: The universe is a mystery. - John: The universe is a mystery. - John: Yikes, it's really stuck isn't it. Would you help me debug my code? - Jane: Sure, what's the problem? - John: I'm not sure. I think it's a bug in the code. - Jane: I'll take a look. - Jane: I think I found the problem. - Jane: It looks like you're not passing the right parameters to the model. - John: Thanks for the help! - Jane: I'm now writing a bot to summarize conversations. I want to make sure it works when the conversation is long. - John: So you need to keep talking with me to generate a long conversation? - Jane: Yes, that's right. - John: Ok, I'll keep talking. What should we talk about? - Jane: I don't know, what do you want to talk about? - John: I don't know, it's nice how CoPilot is doing most of the talking for us. But it definitely gets stuck sometimes. - Jane: I agree, it's nice that CoPilot is doing most of the talking for us. - Jane: But it definitely gets stuck sometimes. - John: Do you know how long it needs to be? - Jane: I think the max length is 1024 tokens. Which is approximately 1024*4= 4096 characters. - John: That's a lot of characters. - Jane: Yes, it is. - John: I'm not sure how much longer I can keep talking. - Jane: I think we're almost there. Let me check. - Jane: I have some bad news, we're only half way there. - John: Oh no, I'm not sure I can keep going. I'm getting tired. - Jane: I'm getting tired too. - John: Maybe there is a large piece of text we can use to generate a long conversation. - Jane: That's a good idea. Let me see if I can find one. Maybe Lorem Ipsum? - John: Yeah, that's a good idea. - Jane: I found a Lorem Ipsum generator. - Jane: Here's a 4096 character Lorem Ipsum text: - Jane: Lorem ipsum dolor sit amet, con - Jane: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc sit amet aliquam - Jane: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc sit amet aliquam - Jane: Darn, it's just repeating stuff now. - John: I think we're done. - Jane: We're not though! We need like 1500 more characters. - John: Oh Canada, our home and native land. - Jane: True patriot love in all thy sons command. - John: With glowing hearts we see thee rise. - Jane: The True North strong and free. - John: From far and wide, O Canada, we stand on guard for thee. - Jane: God keep our land glorious and free. - John: O Canada, we stand on guard for thee. - Jane: O Canada, we stand on guard for thee. - Jane: That was fun, thank you. Let me check now. - Jane: I think we need about 600 more characters. - John: Oh say can you see? - Jane: By the dawn's early light. - John: What so proudly we hailed. - Jane: At the twilight's last gleaming. - John: Whose broad stripes and bright stars. - Jane: Through the perilous fight. - John: O'er the ramparts we watched. - Jane: Were so gallantly streaming. - John: And the rockets' red glare. - Jane: The bombs bursting in air. - John: Gave proof through the night. - Jane: That our flag was still there. - John: Oh say does that star-spangled banner yet wave. - Jane: O'er the land of the free. - John: And the home of the brave. - Jane: Are you a Seattle Kraken Fan? - John: Yes, I am. I love going to the games. - Jane: I'm a Seattle Kraken Fan too. Who is your favorite player? - John: I like watching all the players, but I think my favorite is Matty Beniers. - Jane: Yeah, he's a great player. I like watching him too. I also like watching Jaden Schwartz. - John: Adam Larsson is another good one. The big cat! - Jane: WE MADE IT! It's long enough. Thank you! - John: Can you automate generating long text next time? - Jane: I will. - John: You're welcome. I'm glad we could help. Goodbye! - Jane: Goodbye! - """ - .stripIndent(); - - public static void main(String[] args) throws ConfigurationException { - conversationSummaryPluginAsync(); - getConversationActionItemsAsync(); - getConversationTopicsAsync(); - } - - private static void getConversationActionItemsAsync() { - System.out.println( - "======== SamplePlugins - Conversation Summary Plugin - Action Items ========"); - Kernel kernel = initializeKernel(); - - KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), null); - - Mono> summary = kernel - .invokeAsync( - conversationSummaryPlugin - .get("GetConversationActionItems")) - .withArguments( - KernelArguments.builder() - .withInput(chatTranscript) - .build()); - System.out.println("Generated Action Items:"); - System.out.println(summary.block().getResult()); - } - - private static void getConversationTopicsAsync() { - Kernel kernel = initializeKernel(); - - KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), null); - - Mono> summary = kernel - .invokeAsync(conversationSummaryPlugin.get("GetConversationTopics")) - .withArguments( - KernelArguments.builder() - .withInput(chatTranscript) - .build()); - - System.out.println("Generated Topics:"); - System.out.println(summary.block().getResult()); - } - - private static void conversationSummaryPluginAsync() { - System.out.println( - "======== SamplePlugins - Conversation Summary Plugin - Action Items ========"); - Kernel kernel = initializeKernel(); - - KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), null); - - FunctionResult summary = kernel - .invokeAsync( - conversationSummaryPlugin - .getFunctions() - .get("SummarizeConversation")) - .withArguments( - KernelArguments.builder() - .withInput(chatTranscript) - .build()) - .block(); - - System.out.println("Generated Summary (This may take some time):"); - System.out.println(summary.getResult()); - } - - private static Kernel initializeKernel() { - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - return Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/rag/DocumentSplittingExample.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/rag/DocumentSplittingExample.java deleted file mode 100644 index 549d4f4dd..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/rag/DocumentSplittingExample.java +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.rag; - -import com.microsoft.semantic.kernel.rag.splitting.Chunk; -import com.microsoft.semantic.kernel.rag.splitting.Document; -import com.microsoft.semantic.kernel.rag.splitting.Splitter; -import com.microsoft.semantic.kernel.rag.splitting.TextSplitter; -import com.microsoft.semantic.kernel.rag.splitting.document.TextDocument; -import com.microsoft.semantic.kernel.rag.splitting.overlap.NoOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.CountSplitCondition; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SplitPoint; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandlers; -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import org.apache.pdfbox.io.RandomAccessReadBuffer; -import org.apache.pdfbox.pdfparser.PDFParser; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.text.PDFTextStripper; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class DocumentSplittingExample { - - private static String BENEFITS_DOC = "https://raw.githubusercontent.com/Azure-Samples/azure-search-openai-demo-java/refs/heads/main/data/Benefit_Options.pdf"; - - private static class PDFDocument implements Document { - - private final byte[] pdf; - - private PDFDocument(byte[] pdf) { - this.pdf = pdf; - } - - @Override - public Flux getContent() { - try { - PDFParser parser = new PDFParser( - RandomAccessReadBuffer.createBufferFromStream(new ByteArrayInputStream(pdf))); - PDDocument document = parser.parse(); - String text = new PDFTextStripper().getText(document); - - return Flux.just(text); - } catch (IOException e) { - return Flux.error(e); - } - } - } - - public static void main(String[] args) throws IOException, InterruptedException { - useCustomChunker(); - useInbuiltChunker(); - } - - private static void useInbuiltChunker() throws IOException, InterruptedException { - byte[] pdfBytes = getPdfDoc(); - PDFDocument pdfDoc = new PDFDocument(pdfBytes); - - Splitter splitter = Splitter - .builder() - .maxParagraphsPerChunk(4) - .overlapNPercent(30.0f) - .trimWhitespace() - .build(); - - List chunks = splitter - .splitDocument(pdfDoc) - .collectList() - .block(); - - chunks - .forEach(chunk -> { - System.out.println("========="); - System.out.println(chunk.getContents()); - }); - } - - public static void useCustomChunker() throws IOException, InterruptedException { - - String example = EmbeddedResourceLoader.readFile("example.md", - DocumentSplittingExample.class); - - // Define how we are splitting tokens, in this case we are splitting on headers of an md file - // i.e followed by one or more # characters - TextSplitter textSplitter = (doc, numTokens) -> { - // Split on headers - Pattern pattern = Pattern.compile("(\\r?\\n|\\r)\s*#+", Pattern.MULTILINE); - - Flux splitPoints = Flux.fromStream(pattern.matcher(doc).results()) - .map(window -> window.start()); - - return createWindows(doc, splitPoints); - }; - - // Split into single sections - CountSplitCondition condition = new CountSplitCondition(1, textSplitter); - - Splitter splitter = Splitter - .builder() - .addChunkEndCondition(condition) - // No overlap - .setOverlapCondition(NoOverlapCondition.build()) - // Tidy up the text - .trimWhitespace() - .build(); - - String chunks = splitter - .splitDocument(new TextDocument(example)) - .collectList() - .map(it -> it.stream() - .map(chunk -> chunk.getContents()) - .collect(Collectors.joining("\n============\n"))) - .block(); - - System.out.println(chunks); - } - - /* - * Transforms: [ 2, 10, 20, 100 ] -> [ (0, 2), (2, 10), (10, 20), (20, 100), (100, ) - * ] - */ - private static List createWindows(String doc, Flux splitPoints) { - return Flux.concat( - Flux.just(0), - splitPoints, - Flux.just(doc.length())) - .window(2, 1) - .concatMap(window -> { - return window.collectList() - .flatMap(list -> { - if (list.size() <= 1) { - return Mono.empty(); - } - return Mono.just( - new SplitPoint(list.get(0), list.get(1))); - }); - }) - .collectList() - .block(); - } - - private static byte[] getPdfDoc() throws IOException, InterruptedException { - HttpResponse doc = HttpClient.newHttpClient() - .send(HttpRequest.newBuilder() - .GET() - .uri(URI.create(BENEFITS_DOC)) - .build(), - BodyHandlers.ofByteArray()); - return doc.body(); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example06_TemplateLanguage.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example06_TemplateLanguage.java deleted file mode 100644 index 698a2e1bf..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example06_TemplateLanguage.java +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.template; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService; -import com.microsoft.semantickernel.exceptions.ConfigurationException; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; - -public class Example06_TemplateLanguage { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) throws ConfigurationException { - - System.out.println("======== TemplateLanguage ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - // Load native plugin into the kernel function collection, sharing its functions with prompt templates - // Functions loaded here are available as "time.*" - KernelPlugin time = KernelPluginFactory.createFromObject( - new Time(), "time"); - - kernel = kernel.toBuilder() - .withPlugin(time) - .build(); - - // Prompt Function invoking time.Date and time.Time method functions - String functionDefinition = """ - Today is: {{time.date}} - Current time is: {{time.time}} - - Answer to the following questions using JSON syntax, including the data used. - Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)? - Is it weekend time (weekend/not weekend)? - """; - - // This allows to see the prompt before it's sent to OpenAI - System.out.println("--- Rendered Prompt"); - - var promptTemplate = new KernelPromptTemplateFactory() - .tryCreate(PromptTemplateConfig - .builder() - .withTemplate(functionDefinition) - .build()); - - var renderedPrompt = promptTemplate.renderAsync(kernel, null, null).block(); - System.out.println(renderedPrompt); - - var kindOfDay = KernelFunction.createFromPrompt(functionDefinition) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(100) - .build()) - .withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT) - .build(); - - // Show the result - System.out.println("--- Prompt Function result"); - var result = kernel.invokeAsync(kindOfDay).block(); - System.out.println(result.getResult()); - } - - public static class Time { - - @DefineKernelFunction(name = "date") - public String date() { - return "2021-09-01"; - } - - @DefineKernelFunction(name = "time") - public String time() { - return "12:00:00"; - } - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example56_TemplateMethodFunctionsWithMultipleArguments.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example56_TemplateMethodFunctionsWithMultipleArguments.java deleted file mode 100644 index e26babe61..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example56_TemplateMethodFunctionsWithMultipleArguments.java +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.template; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.text.TextPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Example56_TemplateMethodFunctionsWithMultipleArguments { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - System.out.println("======== TemplateMethodFunctionsWithMultipleArguments ========"); - - var arguments = KernelArguments.builder() - .withVariable("word2", " Potter") - .build(); - - // Load native plugin into the kernel function collection, sharing its functions with prompt templates - // Functions loaded here are available as "text.*" - kernel = kernel.toBuilder() - .withPlugin(KernelPluginFactory.createFromObject(new TextPlugin(), "text")) - .build(); - - // Prompt Function invoking text.Concat method function with named arguments input and input2 where input is a string and input2 is set to a variable from context called word2. - String functionDefinition = "Write a haiku about the following: {{text.Concat input='Harry' input2=$word2}}"; - - // This allows to see the prompt before it's sent to OpenAI - System.out.println("--- Rendered Prompt"); - var promptTemplateFactory = new KernelPromptTemplateFactory(); - var promptTemplate = promptTemplateFactory.tryCreate( - PromptTemplateConfig.builder().withTemplate(functionDefinition).build()); - var renderedPrompt = promptTemplate.renderAsync(kernel, arguments, null).block(); - System.out.println(renderedPrompt); - - // Run the prompt / prompt function - - var haiku = KernelFunctionFromPrompt - .builder() - .withTemplate(functionDefinition) - .withDefaultExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(100) - .build()) - .build(); - - // Show the result - System.out.println("--- Prompt Function result"); - var result = kernel.invokeAsync(haiku).withArguments(arguments).block(); - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example64_MultiplePromptTemplates.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example64_MultiplePromptTemplates.java deleted file mode 100644 index 75568a6e9..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/template/Example64_MultiplePromptTemplates.java +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.syntaxexamples.template; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.semanticfunctions.AggregatorPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import java.util.List; - -public class Example64_MultiplePromptTemplates { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo"); - - public static void main(String[] args) { - System.out.println("======== Example64_MultiplePromptTemplates ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - var kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion) - .build(); - - var templateFactory = new AggregatorPromptTemplateFactory( - List.of( - new KernelPromptTemplateFactory(), - new HandlebarsPromptTemplateFactory())); - - runPrompt(kernel, - "semantic-kernel", - "Hello AI, my name is {{$name}}. What is the origin of my name?", - templateFactory); - runPrompt(kernel, - "handlebars", - "Hello AI, my name is {{name}}. What is the origin of my name?", - templateFactory); - } - - public static void runPrompt(Kernel kernel, String templateFormat, String prompt, - PromptTemplateFactory templateFactory) { - var function = new KernelFunctionFromPrompt.Builder<>() - .withTemplate(prompt) - .withTemplateFormat(templateFormat) - .withPromptTemplateFactory(templateFactory) - .build(); - - var arguments = KernelArguments.builder() - .withVariable("name", "Bob") - .build(); - - var result = kernel.invokeAsync(function).withArguments(arguments).block(); - System.out.println(result.getResult()); - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/util/LocaleParser.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/util/LocaleParser.java deleted file mode 100644 index f4d7f06a2..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/util/LocaleParser.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.util; - -import java.util.Locale; - -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -/** - * Locale parser to support Java 8 and Java 9+ due to JEP 252. - * - *

Supports parsing strings containing languageCode_countryCode and languageCode-countryCode - * styles. - */ -public final class LocaleParser { - - private LocaleParser() { - } - - /** - * Parses the locale. If the input is "en-US", it will return a Locale based on the language - * tag. If the input is "en_US", it will return a Locale based on the language and country code. - * Otherwise, it will return a Locale based on the input. - * - *

'en' 'US' used as example above. - * - * @param locale the locale in String text. - * @return - */ - @SuppressWarnings("StringSplitter") - public static final Locale parseLocale(String locale) { - Locale parsedLocale = null; - - if (locale == null - || "".equals(locale.trim()) - || KernelFunctionParameter.NO_DEFAULT_VALUE.equals(locale)) { - return Locale.getDefault(); - } else if (locale.indexOf("-") > -1) { - parsedLocale = Locale.forLanguageTag(locale); - } else if (locale.indexOf("_") > -1) { - String[] parts = locale.split("_"); - parsedLocale = new Locale(parts[0], parts[1]); - } else { - parsedLocale = new Locale(locale); - } - - return parsedLocale; - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/config.json deleted file mode 100644 index bcdcb51cf..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin loaded from classpath root via resources", - "type": "completion", - "completion": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0 - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/skprompt.txt deleted file mode 100644 index ddd3f836d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionRoot/skprompt.txt +++ /dev/null @@ -1 +0,0 @@ -This is an example \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/config.json deleted file mode 100644 index 89d93f325..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin with a model and service id", - "type": "completion", - "completion": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0, - "service_id": "text-davinci-003", - "model_id": "text-davinci-003" - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/skprompt.txt deleted file mode 100644 index 1483cb399..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/ExamplePlugins/ExampleFunctionWithService/skprompt.txt +++ /dev/null @@ -1 +0,0 @@ -Tell me a joke. \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/config.json deleted file mode 100644 index 93e812d18..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "schema": 1, - "type": "completion", - "description": "Creates a chat response to the user", - "execution_settings": { - "default": { - "max_tokens": 1000, - "temperature": 0 - }, - "gpt-3.5-turbo": { - "model_id": "gpt-3.5-turbo-0613", - "max_tokens": 4000, - "temperature": 0.1 - }, - "gpt-4": { - "model_id": "gpt-4-1106-preview", - "max_tokens": 8000, - "temperature": 0.3 - } - }, - "input_variables": [ - { - "name": "request", - "description": "The user's request.", - "required": true - }, - { - "name": "history", - "description": "The history of the conversation.", - "required": true - } - ] -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/skprompt.txt deleted file mode 100644 index 82ae0242c..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/Chat/skprompt.txt +++ /dev/null @@ -1,3 +0,0 @@ -{{ConversationSummaryPlugin.SummarizeConversation $history}} -User: {{$request}} -Assistant: \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml deleted file mode 100644 index 3fa1dfbc5..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: getIntent -description: Gets the intent of the user. -template: | - Instructions: What is the intent of this request? - Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}. - Choices: {{choices}}. - - {{#each fewShotExamples}} - {{#each this}} - {{content}} - {{/each}} - {{/each}} - - Summary of conversation so far: - {{ConversationSummaryPlugin-SummarizeConversation history}} - - - {{request}} - Intent: -template_format: handlebars -input_variables: - - name: choices - description: The choices for the AI to choose from - default: ContinueConversation, EndConversation - - name: fewShotExamples - description: Few shot examples for the AI to learn from - is_required: true - - name: request - description: The user's request - is_required: true -execution_settings: - default: - max_tokens: 10 - temperature: 0 - gpt-3.5-turbo: - model_id: gpt-35-turbo-2 - max_tokens: 10 - temperature: 0.2 - gpt-4: - model_id: gpt-4-1106-preview - max_tokens: 10 - temperature: 0.2 diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/config.json deleted file mode 100644 index 632a4e045..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": 1, - "description": "Given a scientific white paper abstract, rewrite it to make it more readable", - "execution_settings": { - "default": { - "max_tokens": 4000, - "temperature": 0.0, - "top_p": 1.0, - "presence_penalty": 0.0, - "frequency_penalty": 2.0 - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/skprompt.txt deleted file mode 100644 index 5501e19b7..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/MakeAbstractReadable/skprompt.txt +++ /dev/null @@ -1,5 +0,0 @@ -{{$input}} - -== -Summarize, using a user friendly, using simple grammar. Don't use subjects like "we" "our" "us" "your". -== \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/config.json deleted file mode 100644 index 4ffaccb55..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": 1, - "description": "Automatically generate compact notes for any text or text document.", - "execution_settings": { - "default": { - "max_tokens": 256, - "temperature": 0.0, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/skprompt.txt deleted file mode 100644 index b3f4d203b..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Notegen/skprompt.txt +++ /dev/null @@ -1,21 +0,0 @@ -Analyze the following extract taken from a document. -- Produce key points for memory. -- Give memory a name. -- Extract only points worth remembering. -- Be brief. Conciseness is very important. -- Use broken English. -You will use this memory to analyze the rest of this document, and for other relevant tasks. - -[Input] -My name is Macbeth. I used to be King of Scotland, but I died. My wife's name is Lady Macbeth and we were married for 15 years. We had no children. Our beloved dog Toby McDuff was a famous hunter of rats in the forest. -My story was immortalized by Shakespeare in a play. -+++++ -Family History -- Macbeth, King Scotland -- Wife Lady Macbeth, No Kids -- Dog Toby McDuff. Hunter, dead. -- Shakespeare play - -[Input] -[[{{$input}}]] -+++++ diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/config.json deleted file mode 100644 index f2f2ce517..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/config.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "schema": 1, - "description": "Summarize given text or any text document", - "execution_settings": { - "default": { - "max_tokens": 512, - "temperature": 0.0, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - } - }, - "input_variables": [ - { - "name": "input", - "type": "java.lang.String", - "description": "Text to summarize", - "default": "", - "is_required": true - } - ] -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/skprompt.txt deleted file mode 100644 index 5597e1350..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Summarize/skprompt.txt +++ /dev/null @@ -1,23 +0,0 @@ -[SUMMARIZATION RULES] -DONT WASTE WORDS -USE SHORT, CLEAR, COMPLETE SENTENCES. -DO NOT USE BULLET POINTS OR DASHES. -USE ACTIVE VOICE. -MAXIMIZE DETAIL, MEANING -FOCUS ON THE CONTENT - -[BANNED PHRASES] -This article -This document -This page -This material -[END LIST] - -Summarize: -Hello how are you? -+++++ -Hello - -Summarize this -{{$input}} -+++++ \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/config.json deleted file mode 100644 index f2a46c542..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": 1, - "description": "Analyze given text or document and extract key topics worth remembering", - "execution_settings": { - "default": { - "max_tokens": 128, - "temperature": 0.0, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/skprompt.txt deleted file mode 100644 index cb7a28c13..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/SummarizePlugin/Topics/skprompt.txt +++ /dev/null @@ -1,28 +0,0 @@ -Analyze the following extract taken from a document and extract key topics. -- Topics only worth remembering. -- Be brief. Short phrases. -- Can use broken English. -- Conciseness is very important. -- Topics can include names of memories you want to recall. -- NO LONG SENTENCES. SHORT PHRASES. -- Return in JSON -[Input] -My name is Macbeth. I used to be King of Scotland, but I died. My wife's name is Lady Macbeth and we were married for 15 years. We had no children. Our beloved dog Toby McDuff was a famous hunter of rats in the forest. -My tragic story was immortalized by Shakespeare in a play. -[Output] -{ - "topics": [ - "Macbeth", - "King of Scotland", - "Lady Macbeth", - "Dog", - "Toby McDuff", - "Shakespeare", - "Play", - "Tragedy" - ] -} -+++++ -[Input] -{{$input}} -[Output] \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/config.json deleted file mode 100644 index c03553d76..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "schema": 1, - "type": "completion", - "description": "Turn a scenario into a short and entertaining poem.", - "completion": { - "max_tokens": 200, - "temperature": 0.5, - "top_p": 0.0, - "presence_penalty": 0.0, - "frequency_penalty": 0.0 - }, - "input": { - "parameters": [ - { - "name": "input", - "description": "The scenario to turn into a poem.", - "defaultValue": "" - } - ] - } -} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/skprompt.txt deleted file mode 100644 index d85146e03..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins/WriterPlugin/ShortPoem/skprompt.txt +++ /dev/null @@ -1,2 +0,0 @@ -Generate a short funny poem or limerick to explain the given event. Be creative and be funny. Let your imagination run wild. -Event: {{$input}} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/config.json deleted file mode 100644 index 30b3c891b..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin loaded via resources", - "execution_settings": { - "default": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0 - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt deleted file mode 100644 index ddd3f836d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt +++ /dev/null @@ -1 +0,0 @@ -This is an example \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-system-prompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-system-prompt.txt deleted file mode 100644 index e358d3a91..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-system-prompt.txt +++ /dev/null @@ -1,5 +0,0 @@ -You are an AI assistant that helps people find information. -The chat started at: {{ $startTime }} -The current time is: {{ time.now }} -Text selected: -{{ $selectedText }} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-context.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-context.txt deleted file mode 100644 index dec71acb4..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-context.txt +++ /dev/null @@ -1 +0,0 @@ -The central Sahara is hyperarid, with sparse vegetation. The northern and southern reaches of the desert, along with the highlands, have areas of sparse grassland and desert shrub, with trees and taller shrubs in wadis, where moisture collects. In the central, hyperarid region, there are many subdivisions of the great desert: Tanezrouft, the Ténéré, the Libyan Desert, the Eastern Desert, the Nubian Desert and others. These extremely arid areas often receive no rain for years. \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-prompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-prompt.txt deleted file mode 100644 index 6b13c8004..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/30-user-prompt.txt +++ /dev/null @@ -1 +0,0 @@ -{{ time.now }}: {{ $userMessage }} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/duke.png b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/duke.png deleted file mode 100644 index 31793b089..000000000 Binary files a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/duke.png and /dev/null differ diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStory.yaml b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStory.yaml deleted file mode 100644 index fc5ecd88f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStory.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: GenerateStory -template: | - Tell a story about {{$topic}} that is {{$length}} sentences long. -template_format: semantic-kernel -description: A function that generates a story about a topic. -input_variables: - - name: topic - description: The topic of the story. - is_required: true - - name: length - description: The number of sentences in the story. - is_required: true -output_variable: - description: The generated story. -execution_settings: - default: - temperature: 0.6 diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStoryHandlebars.yaml b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStoryHandlebars.yaml deleted file mode 100644 index 88bc4d7c3..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/GenerateStoryHandlebars.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: GenerateStory -template: | - Tell a story about {{topic}} that is {{length}} sentences long. -template_format: handlebars -description: A function that generates a story about a topic. -input_variables: - - name: topic - description: The topic of the story. - is_required: true - - name: length - description: The number of sentences in the story. - is_required: true -output_variable: - description: The generated story. -execution_settings: - service1: - model_id: gpt-4 - temperature: 0.6 - service2: - model_id: gpt-3 - temperature: 0.4 - default: - temperature: 0.5 diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/applicationinsights.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/applicationinsights.json deleted file mode 100644 index a5c0a2275..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/java/applicationinsights.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "connectionString": "InstrumentationKey=00000000-0000-0000-0000-0000-000000000000", - "preview": { - "processors": [ - { - "type": "span", - "include": { - "matchType": "regexp", - "spanNames": [ - ".*" - ] - } - } - ] - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/config.json deleted file mode 100644 index 47f85399f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin loaded via resources", - "type": "completion", - "completion": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0 - }, - "input": { - "parameters": [ - { - "name": "input", - "description": "Question to answer" - }, - { - "name": "sources", - "description": "Information used to answer the question" - } - ] - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/skprompt.txt deleted file mode 100644 index fdc3dcfaf..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/Answer/AnswerQuestion/skprompt.txt +++ /dev/null @@ -1,30 +0,0 @@ -Using the information below and ONLY the information below, answer the question: - -[EXAMPLES] -[EXAMPLE 1] -[INFORMATION] -- My computer is hot -- My computers fan is on -[END INFORMATION] -Question: What temperature is my computer? -Answer: Your computer is hot -[END EXAMPLE 2] - - -[EXAMPLE 2] -[INFORMATION] -- The house is red -- The house has 5 bed rooms -[END INFORMATION] -Question: Where is the house? -Answer: I do not have enough information to answer that. -[END EXAMPLE 2] - -[END EXAMPLES] - -[INFORMATION] -{{$sources}} -[END INFORMATION] - -Question: {{$input}} -Answer: \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/config.json b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/config.json deleted file mode 100644 index 30b3c891b..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin loaded via resources", - "execution_settings": { - "default": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0 - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt deleted file mode 100644 index ddd3f836d..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt +++ /dev/null @@ -1 +0,0 @@ -This is an example \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/require_context_variable_planner_prompt.txt b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/require_context_variable_planner_prompt.txt deleted file mode 100644 index c949a424f..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/javaspecific/require_context_variable_planner_prompt.txt +++ /dev/null @@ -1,118 +0,0 @@ -Create an XML plan step by step, to satisfy the goal given. -To create a plan, follow these steps: -0. The plan should be as short as possible. -1. From a create a as a series of . -2. Before using any function in a plan, check that it is present in the most recent [AVAILABLE FUNCTIONS] list. If it is not, do not use it. Do not assume that any function that was previously defined or used in another plan or in [EXAMPLES] is automatically available or compatible with the current plan. -3. Only use functions that are required for the given goal. -4. A function has a single 'input' and a single 'output' which are both strings and not objects. -5. The 'output' from each function is automatically passed as 'input' to the subsequent . -6. 'input' does not need to be specified if it consumes the 'output' of the previous function. -7. To save an 'output' from a , to pass into a future , use "/> -8. To save an 'output' from a , to return as part of a plan result, use "/> -9. Append an "END" XML comment at the end of the plan. - -[EXAMPLES] -[AVAILABLE FUNCTIONS] - - EmailConnector.LookupContactEmail: - description: looks up a contact and retrieves their email address - inputs: - - input: the name to look up - - EmailConnector.EmailTo: - description: email the input text to a recipient - inputs: - - input: the text to email - - recipient: the recipient's email address. Multiple addresses may be included if separated by ';'. - - LanguageHelpers.TranslateTo: - description: translate the input to another language - inputs: - - input: the text to translate - - translate_to_language: the language to translate to - - SummarizeSkill.Summarize: - description: summarize input text - inputs: - - input: the text to summarize - -[END AVAILABLE FUNCTIONS] - -Summarize the input, then translate to japanese and email it to Martin - - - - - - - -[AVAILABLE FUNCTIONS] - - _GLOBAL_FUNCTIONS_.GetEmailAddress: - description: Gets email address for given contact - inputs: - - input: the name to look up - - _GLOBAL_FUNCTIONS_.SendEmail: - description: email the input text to a recipient - inputs: - - input: the text to email - - recipient: the recipient's email address. Multiple addresses may be included if separated by ';'. - - AuthorAbility.Summarize: - description: summarizes the input text - inputs: - - input: the text to summarize - - Magician.TranslateTo: - description: translate the input to another language - inputs: - - input: the text to translate - - translate_to_language: the language to translate to - -[END AVAILABLE FUNCTIONS] - -Summarize an input, translate to french, and e-mail to John Doe - - - - - - - -[AVAILABLE FUNCTIONS] - - _GLOBAL_FUNCTIONS_.NovelOutline : - description: Outlines the input text as if it were a novel - inputs: - - input: the title of the novel to outline - - chapterCount: the number of chapters to outline - - Emailer.EmailTo: - description: email the input text to a recipient - inputs: - - input: the text to email - - recipient: the recipient's email address. Multiple addresses may be included if separated by ';'. - - Everything.Summarize: - description: summarize input text - inputs: - - input: the text to summarize - -[END AVAILABLE FUNCTIONS] - -Create an outline for a children's book with 3 chapters about a group of kids in a club and then summarize it. - - - - - -[END EXAMPLES] - -[AVAILABLE FUNCTIONS] - -{{$available_functions}} - -[END AVAILABLE FUNCTIONS] - -{{$input}} diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/rag/example.md b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/rag/example.md deleted file mode 100644 index 725913439..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/com/microsoft/semantickernel/samples/syntaxexamples/rag/example.md +++ /dev/null @@ -1,22 +0,0 @@ -## Section 1 - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna -aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis -aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint -occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - -## Section 2 - -Another section. - -### Subsection 1 - -1, 2, 3, 4, 5, 6, 7, 8, 9, 10. - -# Section 3 - -This is the last section. - -``` -some code -``` \ No newline at end of file diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/log4j2.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/log4j2.xml deleted file mode 100644 index f34bc2011..000000000 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/booking-agent-m365/pom.xml b/samples/semantickernel-demos/booking-agent-m365/pom.xml deleted file mode 100644 index 60bc7ffbc..000000000 --- a/samples/semantickernel-demos/booking-agent-m365/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-demos - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - booking-agent-m365 - Booking agent with M365 - Booking agent using M365 - - - 17 - 17 - UTF-8 - - - - - org.apache.logging.log4j - log4j-api - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - - com.azure - azure-identity - - - - com.microsoft.graph - microsoft-graph - 6.13.0 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingAgent.java b/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingAgent.java deleted file mode 100644 index 11f7bea77..000000000 --- a/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingAgent.java +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.azure.identity.InteractiveBrowserCredential; -import com.azure.identity.InteractiveBrowserCredentialBuilder; -import com.microsoft.graph.serviceclient.GraphServiceClient; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.util.List; -import java.util.Scanner; - -public class BookingAgent { - - // Config for OpenAI - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo-2"); - - // Config for Graph - // https://learn.microsoft.com/en-us/graph/tutorials/java?tabs=aad&tutorial-step=1 - private static final String TENANT_ID = System.getenv("TENANT_ID"); - private static final String CLIENT_ID = System.getenv("CLIENT_ID"); - // Booking Business ID - private static final String BOOKING_BUSINESS_ID = System.getenv("BOOKING_BUSINESS_ID"); - // Service ID for the booking business - private static final String SERVICE_ID = System.getenv("SERVICE_ID"); - // Must match the redirect URL in the Azure AD app registration - private static final String REDIRECT_URL = System.getenv("REDIRECT_URL"); - private static GraphServiceClient userClient; - - public static void initializeGraph() { - InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredentialBuilder() - .clientId(CLIENT_ID) - .tenantId(TENANT_ID) - .redirectUrl(REDIRECT_URL) - .build(); - - userClient = new GraphServiceClient(interactiveBrowserCredential, - "User.Read", "BookingsAppointment.ReadWrite.All"); - } - - public static void main(String[] args) throws NoSuchMethodException { - System.out.println("======== Open AI - Booking System ========"); - - OpenAIAsyncClient client; - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - initializeGraph(); - - KernelPlugin plugin = KernelPluginFactory.createFromObject(new BookingPlugin( - userClient, - BOOKING_BUSINESS_ID, - SERVICE_ID, - "UTC"), "BookingRestaurant"); - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - Kernel kernel = Kernel.builder() - .withPlugin(plugin) - .withAIService(ChatCompletionService.class, chat) - .build(); - - ChatHistory chatHistory = new ChatHistory(); - - Scanner scanner = new Scanner(System.in); - String userMessage; - System.out.println("User > "); - - while ((userMessage = scanner.nextLine()) != null) { - - chatHistory.addUserMessage(userMessage); - InvocationContext invocationContext = InvocationContext.builder() - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .build(); - - List> messages = chat - .getChatMessageContentsAsync(chatHistory, kernel, invocationContext) - .block(); - - ChatMessageContent result = CollectionUtil.getLastOrNull(messages); - - chatHistory.addAssistantMessage(result.getContent()); - - System.out.println("System > " + result); - System.out.println("User > "); - } - } -} diff --git a/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingPlugin.java b/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingPlugin.java deleted file mode 100644 index 68c1ff95e..000000000 --- a/samples/semantickernel-demos/booking-agent-m365/src/main/java/com/microsoft/semantickernel/BookingPlugin.java +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel; - -import com.microsoft.graph.models.BookingAppointment; -import com.microsoft.graph.models.BookingCustomerInformation; -import com.microsoft.graph.models.BookingCustomerInformationBase; -import com.microsoft.graph.models.DateTimeTimeZone; -import com.microsoft.graph.models.Location; -import com.microsoft.graph.models.User; -import com.microsoft.graph.serviceclient.GraphServiceClient; -import com.microsoft.kiota.PeriodAndDuration; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -import java.time.Duration; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; - -public class BookingPlugin { - public static final int BOOKING_HOURS = 2; - private final GraphServiceClient graphServiceClient; - private final String bookingBusinessId; - private final String serviceId; - private final String userTimeZone; - - public BookingPlugin(GraphServiceClient graphServiceClient, - String bookingBusinessId, - String serviceId, - String userTimeZone) { - this.graphServiceClient = graphServiceClient; - this.bookingBusinessId = bookingBusinessId; - this.serviceId = serviceId; - this.userTimeZone = userTimeZone; - } - - @DefineKernelFunction(name = "bookTable", description = "Book a table at a restaurant", returnType = "string") - public String bookTable( - @KernelFunctionParameter(name = "restaurant", description = "The name of the restaurant") String restaurant, - @KernelFunctionParameter(name = "date", description = "The date of the reservation in UTC", type = OffsetDateTime.class) OffsetDateTime date, - @KernelFunctionParameter(name = "partySize", description = "The number of people in the party", type = int.class) int partySize, - @KernelFunctionParameter(name = "customerName", description = "The name of the customer") String customerName, - @KernelFunctionParameter(name = "customerEmail", description = "The email of the customer") String customerEmail, - @KernelFunctionParameter(name = "customerPhone", description = "The phone of the customer") String customerPhone) { - System.out.println("System > Do you want to book a table at " + restaurant + " on " + date - + " for " + partySize + " people?"); - System.out.println("System > Please confirm the booking by typing 'yes' or 'no'"); - Scanner scanner = new Scanner(System.in); - String response = scanner.nextLine().toLowerCase(); - - if (response.equals("yes")) { - BookingAppointment bookingAppointment = new BookingAppointment(); - bookingAppointment.setOdataType("#microsoft.graph.bookingAppointment"); - bookingAppointment.setCustomerTimeZone(userTimeZone); - bookingAppointment.setSmsNotificationsEnabled(false); - DateTimeTimeZone endDateTime = new DateTimeTimeZone(); - endDateTime.setOdataType("#microsoft.graph.dateTimeTimeZone"); - endDateTime.setDateTime(date.plusHours(BOOKING_HOURS).toString()); - endDateTime.setTimeZone("UTC"); - bookingAppointment.setEndDateTime(endDateTime); - bookingAppointment.setIsLocationOnline(false); - bookingAppointment.setOptOutOfCustomerEmail(false); - bookingAppointment.setAnonymousJoinWebUrl(null); - PeriodAndDuration postBuffer = PeriodAndDuration.ofDuration(Duration.parse("PT10M")); - bookingAppointment.setPostBuffer(postBuffer); - PeriodAndDuration preBuffer = PeriodAndDuration.ofDuration(Duration.parse("PT5M")); - bookingAppointment.setPreBuffer(preBuffer); - bookingAppointment.setServiceId(serviceId); - Location serviceLocation = new Location(); - serviceLocation.setOdataType("#microsoft.graph.location"); - serviceLocation.setDisplayName(restaurant); - bookingAppointment.setServiceLocation(serviceLocation); - DateTimeTimeZone startDateTime = new DateTimeTimeZone(); - startDateTime.setOdataType("#microsoft.graph.dateTimeTimeZone"); - startDateTime.setDateTime(date.toString()); - startDateTime.setTimeZone("UTC"); - bookingAppointment.setStartDateTime(startDateTime); - bookingAppointment.setMaximumAttendeesCount(partySize); - bookingAppointment.setFilledAttendeesCount(partySize); - bookingAppointment.setCustomers(List.of(new BookingCustomerInformation() { - { - setOdataType("#microsoft.graph.bookingCustomerInformation"); - new BookingCustomerInformationBase() { - { - setOdataType("#microsoft.graph.bookingCustomerInformationBase"); - setName(customerName); - setEmailAddress(customerEmail); - setPhone(customerPhone); - } - }; - } - })); - - graphServiceClient.solutions().bookingBusinesses() - .byBookingBusinessId(bookingBusinessId) - .appointments().post(bookingAppointment); - - return "Booking successful!"; - } - - return "Booking aborted by the user"; - } - - @DefineKernelFunction(name = "listReservations", description = "List all reservations for a customer") - public List listReservations( - @KernelFunctionParameter(name = "customerName", description = "The name of the customer") String customerName) { - List appointments = graphServiceClient.solutions().bookingBusinesses() - .byBookingBusinessId(bookingBusinessId).appointments().get().getValue(); - - List reservations = new ArrayList<>(); - for (BookingAppointment appointment : appointments) { - if (appointment.getCustomers() != null && !appointment.getCustomers().isEmpty() && - appointment.getCustomers().get(0).getBackingStore().get("name") - .equals(customerName)) { - String reservation = "Restaurant: " + - appointment.getServiceLocation().getDisplayName() + - "Date: " + - appointment.getStartDateTime().getDateTime() + - "Party size: " + - appointment.getMaximumAttendeesCount(); - - reservations.add(reservation); - } - } - - return reservations; - } - - private BookingAppointment getAppointment(String restaurant, String customerName, - OffsetDateTime date) { - List appointments = graphServiceClient.solutions().bookingBusinesses() - .byBookingBusinessId(bookingBusinessId).appointments().get().getValue(); - - for (BookingAppointment appointment : appointments) { - if (appointment.getServiceLocation().getDisplayName().equals(restaurant) - && appointment.getCustomers() != null && !appointment.getCustomers().isEmpty() - && appointment.getCustomers().get(0).getBackingStore().get("name") - .equals(customerName) - && OffsetDateTime.parse(appointment.getStartDateTime().getDateTime()) - .equals(date)) { - return appointment; - } - } - return null; - } - - @DefineKernelFunction(name = "cancelReservation", description = "Cancel a reservation at a restaurant", returnType = "string") - public String cancelReservation( - @KernelFunctionParameter(name = "restaurant", description = "The name of the restaurant") String restaurant, - @KernelFunctionParameter(name = "date", description = "The date of the reservation in UTC", type = OffsetDateTime.class) OffsetDateTime date, - @KernelFunctionParameter(name = "customerName", description = "The name of the customer") String customerName) { - - System.out.println("System > [Cancelling a reservation for " + customerName + " at " - + restaurant + " on " + date + "]"); - BookingAppointment appointment = getAppointment(restaurant, customerName, date); - - graphServiceClient.solutions().bookingBusinesses().byBookingBusinessId(bookingBusinessId) - .appointments().byBookingAppointmentId(appointment.getId()).delete(); - - return "Reservation cancelled"; - } -} diff --git a/samples/semantickernel-demos/booking-agent-m365/src/main/resources/log4j2.xml b/samples/semantickernel-demos/booking-agent-m365/src/main/resources/log4j2.xml deleted file mode 100644 index 267d17566..000000000 --- a/samples/semantickernel-demos/booking-agent-m365/src/main/resources/log4j2.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/pom.xml b/samples/semantickernel-demos/pom.xml deleted file mode 100644 index c19477a7c..000000000 --- a/samples/semantickernel-demos/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-demos - pom - semantic-kernel-demos - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - - - booking-agent-m365 - semantickernel-spring-starter - sk-presidio-sample - - diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml deleted file mode 100644 index 8db11dcd1..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-demos - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-spring-starter - Semantic Kernel Spring Boot Starter - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - org.slf4j - slf4j-api - - - org.springframework.boot - spring-boot-test - 3.3.2 - test - - - org.assertj - assertj-core - 3.27.7 - test - - - org.springframework.boot - spring-boot-autoconfigure - 3.3.2 - - - org.springframework.boot - spring-boot - 3.3.11 - - - org.springframework - spring-test - 6.1.10 - test - - - com.azure - azure-identity - 1.12.2 - - - org.junit.jupiter - junit-jupiter-api - 5.10.3 - test - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/AzureOpenAIConnectionProperties.java b/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/AzureOpenAIConnectionProperties.java deleted file mode 100644 index 643006f8b..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/AzureOpenAIConnectionProperties.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.starter; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(AzureOpenAIConnectionProperties.CONFIG_PREFIX) -public class AzureOpenAIConnectionProperties { - - public static final String CONFIG_PREFIX = "client.azureopenai"; - - /** - * Azure OpenAI API endpoint.From the Azure AI OpenAI at 'Resource Management' select `Keys and - * Endpoint` and find it on the right side. - */ - private String endpoint; - - /** - * Azure OpenAI API key.From the Azure AI OpenAI at 'Resource Management' select `Keys and - * Endpoint` and find it on the right side. - */ - private String key; - - /** - * Azure OpenAI API deployment name specified in the Azure Open AI studio under Management -> - * Deployments. - */ - private String deploymentName; - - public String getEndpoint() { - return endpoint; - } - - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getDeploymentName() { - return deploymentName; - } - - public void setDeploymentName(String deploymentName) { - this.deploymentName = deploymentName; - } -} diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/SemanticKernelAutoConfiguration.java b/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/SemanticKernelAutoConfiguration.java deleted file mode 100644 index b1d66cc07..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/java/com/microsoft/semantickernel/starter/SemanticKernelAutoConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.starter; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.util.Assert; - -@SpringBootApplication(scanBasePackages = "com.microsoft.semantickernel.starter") -@AutoConfiguration -@EnableConfigurationProperties(AzureOpenAIConnectionProperties.class) -public class SemanticKernelAutoConfiguration { - - private static final Logger LOGGER = LoggerFactory.getLogger( - SemanticKernelAutoConfiguration.class); - - private static String setModelID(AzureOpenAIConnectionProperties connectionProperties) { - String modelId; - if (connectionProperties.getDeploymentName() == null) { - modelId = "text-davinci-003"; - LOGGER.warn( - "No deployment name specified, using default model id: " + modelId); - } else { - modelId = connectionProperties.getDeploymentName(); - LOGGER.info("Using model id: " + modelId); - } - return modelId; - } - - /** - * Creates a {@link OpenAIAsyncClient} with the endpoint and key specified in the - * {@link AzureOpenAIConnectionProperties}. - * - * @param connectionProperties the {@link AzureOpenAIConnectionProperties} to use - * @return the {@link OpenAIAsyncClient} - */ - @Bean - @ConditionalOnClass(OpenAIAsyncClient.class) - @ConditionalOnMissingBean - public OpenAIAsyncClient openAIAsyncClient( - AzureOpenAIConnectionProperties connectionProperties) { - Assert.hasText(connectionProperties.getEndpoint(), "Azure OpenAI endpoint must be set"); - Assert.hasText(connectionProperties.getKey(), "Azure OpenAI key must be set"); - return new OpenAIClientBuilder() - .endpoint(connectionProperties.getEndpoint()) - .credential(new AzureKeyCredential(connectionProperties.getKey())) - .buildAsyncClient(); - } - - /** - * Creates a {@link Kernel} with a default - * {@link com.microsoft.semantickernel.services.AIService} that uses the - * {@link com.microsoft.semantickernel.chatcompletion;} with the model id specified in the - * {@link AzureOpenAIConnectionProperties} as DeploymentName. - * - * @param client the {@link OpenAIAsyncClient} to use - * @return the {@link Kernel} - */ - @Bean - public Kernel semanticKernel(OpenAIAsyncClient client, - AzureOpenAIConnectionProperties connectionProperties) { - return Kernel.builder() - .withAIService(TextGenerationService.class, - OpenAITextGenerationService.builder() - .withModelId(setModelID(connectionProperties)) - .withOpenAIAsyncClient(client) - .build()) - .build(); - } -} diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/resources/application.properties b/samples/semantickernel-demos/semantickernel-spring-starter/src/main/resources/application.properties deleted file mode 100644 index 93406a1e9..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -client.azureopenai.key=yourkey -client.azureopenai.endpoint=yourendpoint -client.azureopenai.deploymentname=davinci-002 \ No newline at end of file diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/AzureOpenAIConnectionPropertiesTest.java b/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/AzureOpenAIConnectionPropertiesTest.java deleted file mode 100644 index 56fd962ad..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/AzureOpenAIConnectionPropertiesTest.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.azureopenai; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.microsoft.semantickernel.starter.AzureOpenAIConnectionProperties; -import com.microsoft.semantickernel.starter.SemanticKernelAutoConfiguration; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.test.context.ActiveProfiles; - -@ActiveProfiles("test") -public class AzureOpenAIConnectionPropertiesTest { - - ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withPropertyValues( - // @formatter:off - "client.azureopenai.key=TEST_KEY", - "client.azureopenai.endpoint=TEST_ENDPOINT", - "client.azureopenai.deploymentname=TEST_DEPLOYMENT_NAME" - - // @formatter:on - ) - .withConfiguration( - AutoConfigurations.of(SemanticKernelAutoConfiguration.class)); - - @Test - public void ConnectionPropertiesTest() { - contextRunner.run( - context -> { - AzureOpenAIConnectionProperties props = context - .getBean(AzureOpenAIConnectionProperties.class); - assertNotNull(props.getEndpoint()); - assertNotNull(props.getKey()); - assertNotNull(props.getDeploymentName()); - }); - } -} diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/SemanticKernelAutoConfigurationTest.java b/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/SemanticKernelAutoConfigurationTest.java deleted file mode 100644 index fa7419f4a..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/java/com/microsoft/semantickernel/azureopenai/SemanticKernelAutoConfigurationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.azureopenai; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.starter.AzureOpenAIConnectionProperties; -import com.microsoft.semantickernel.starter.SemanticKernelAutoConfiguration; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -@EnableConfigurationProperties(AzureOpenAIConnectionProperties.class) -@SpringBootTest(classes = SemanticKernelAutoConfiguration.class) -public class SemanticKernelAutoConfigurationTest { - - @Autowired - Kernel kernel; - - @Test - public void testSemanticKernelAutoConfig() { - ApplicationContextRunner runner = new ApplicationContextRunner(); - runner.withPropertyValues( - // @formatter:off - "client.azureopenai.key=TEST_KEY", - "client.azureopenai.endpoint=TEST_ENDPOINT" - // @formatter:on - ); - runner.withConfiguration(AutoConfigurations.of(SemanticKernelAutoConfiguration.class)); - runner.run( - context -> { - assertNotNull(kernel); - }); - } -} diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/application.properties b/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/application.properties deleted file mode 100644 index 93406a1e9..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -client.azureopenai.key=yourkey -client.azureopenai.endpoint=yourendpoint -client.azureopenai.deploymentname=davinci-002 \ No newline at end of file diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/log4j2.xml b/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/log4j2.xml deleted file mode 100644 index 50a638f0d..000000000 --- a/samples/semantickernel-demos/semantickernel-spring-starter/src/test/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/sk-presidio-sample/.mvn/jvm.config b/samples/semantickernel-demos/sk-presidio-sample/.mvn/jvm.config deleted file mode 100644 index 32599cefe..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/.mvn/jvm.config +++ /dev/null @@ -1,10 +0,0 @@ ---add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED ---add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED ---add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ---add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/samples/semantickernel-demos/sk-presidio-sample/.mvn/wrapper/maven-wrapper.properties b/samples/semantickernel-demos/sk-presidio-sample/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 6d3a56651..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# 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. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/samples/semantickernel-demos/sk-presidio-sample/README.md b/samples/semantickernel-demos/sk-presidio-sample/README.md deleted file mode 100644 index fe9f4c4e2..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Presidio Sample - -This sample demonstrates how to use Presidio with Semantic Kernel to redact sensitive data from a prompt. A sample -output from this example is shown below: - -``` -============================== -Input text is: -The users name is: Steven. -Steven has account number 012345612. -Steven was born in New York and their mother is Sally. -============================== -Anonymised text is: -The users name is: PERSON4. -PERSON4 has account number AU_ACN3. -PERSON4 was born in LOCATION1 and their mother is PERSON2. - -============================== -User Question: -Question: Where was the user born? -============================== -Anonymised response: -The user was born in LOCATION1. -============================== -Deanonymised response: -The user was born in New York. - -============================== -User Question: -Question: Who is the users mother? -============================== -Anonymised response: -The user's mother is PERSON2. -============================== -Deanonymised response: -The user's mother is Sally. -``` - -# App structure - -The [semantickernel-presidio-plugin](..%2F..%2Fsemantickernel-sample-plugins%2Fsemantickernel-presidio-plugin) plugin -takes user text and runs it through Presidio to redact sensitive data. The plugin then returns the redacted text. The -redacted information is then sent to an LLM for processing. The response is then de-anonymised. - -# Build and Run - -As this example depends on running Presidio, it run within docker containers using docker compose. - -- Before building and running ensure that you have run `./mvnw install` on the semantic kernel you wish to use. -- Copy [env.example](env.example) to `.env` and update the values as needed. -- Run [buildAndRun.sh](buildAndRun.sh) \ No newline at end of file diff --git a/samples/semantickernel-demos/sk-presidio-sample/buildAndRun.sh b/samples/semantickernel-demos/sk-presidio-sample/buildAndRun.sh deleted file mode 100755 index 43a1c466d..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/buildAndRun.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -eux - -./mvnw package - -docker-compose build && docker-compose up \ No newline at end of file diff --git a/samples/semantickernel-demos/sk-presidio-sample/docker-compose.yml b/samples/semantickernel-demos/sk-presidio-sample/docker-compose.yml deleted file mode 100644 index 87435525b..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/docker-compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: '3.6' -services: - presidio-analyzer: - image: "mcr.microsoft.com/presidio-analyzer" - ports: - - 3001:3000 - logging: - driver: none - presidio-anonymizer: - image: "mcr.microsoft.com/presidio-anonymizer" - ports: - - 3000:3000 - logging: - driver: none - sk-presidio-sample: - image: "sk-presidio-sample" - depends_on: - - presidio-anonymizer - - presidio-analyzer - build: - context: . - dockerfile: ./sk-presidio-sample-dockerfile - secrets: - - ai-config -secrets: - ai-config: - file: ./.env - diff --git a/samples/semantickernel-demos/sk-presidio-sample/env.example b/samples/semantickernel-demos/sk-presidio-sample/env.example deleted file mode 100644 index 85a2b7439..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/env.example +++ /dev/null @@ -1,7 +0,0 @@ -# If OpenAI -#CLIENT_KEY="" - -# If Azure OpenAI -#USE_AZURE_CLIENT=true -#CLIENT_ENDPOINT="" -#AZURE_CLIENT_KEY="" diff --git a/samples/semantickernel-demos/sk-presidio-sample/mvnw b/samples/semantickernel-demos/sk-presidio-sample/mvnw deleted file mode 100755 index 8d937f4c1..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/semantickernel-demos/sk-presidio-sample/pom.xml b/samples/semantickernel-demos/sk-presidio-sample/pom.xml deleted file mode 100644 index 079b5af0f..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-demos - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - sk-presidio-sample - Presidio Sample - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - com.microsoft.semantic-kernel - semantickernel-presidio-plugin - ${project.version} - - - - org.slf4j - slf4j-api - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - maven-assembly-plugin - - - - com.microsoft.semantickernel.Main - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-demos/sk-presidio-sample/scripts/run.sh b/samples/semantickernel-demos/sk-presidio-sample/scripts/run.sh deleted file mode 100644 index 7578ab41b..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/scripts/run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# It takes some time for presidio to start, wait for it -sleep 10 - -set -a -. /run/secrets/ai-config -set +a - -java -jar sk-presidio-sample.jar \ No newline at end of file diff --git a/samples/semantickernel-demos/sk-presidio-sample/sk-presidio-sample-dockerfile b/samples/semantickernel-demos/sk-presidio-sample/sk-presidio-sample-dockerfile deleted file mode 100644 index 7a5102a23..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/sk-presidio-sample-dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -###################################################### -## Build Deployment -FROM mcr.microsoft.com/openjdk/jdk:21-ubuntu as presidio-sk-sample-app - -COPY --chown=app:app scripts/run.sh /home/app/ - -RUN chmod +x /home/app/run.sh - -WORKDIR /home/app -USER app - -COPY target/sk-presidio-sample-*-jar-with-dependencies.jar /home/app/sk-presidio-sample.jar - -CMD /home/app/run.sh - diff --git a/samples/semantickernel-demos/sk-presidio-sample/src/main/java/com/microsoft/semantickernel/Main.java b/samples/semantickernel-demos/sk-presidio-sample/src/main/java/com/microsoft/semantickernel/Main.java deleted file mode 100644 index ad14c3caf..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/src/main/java/com/microsoft/semantickernel/Main.java +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.presidio.AnonymizedText; -import com.microsoft.semantickernel.presidio.AnonymizedTextConverter; -import com.microsoft.semantickernel.presidio.RedactorPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.ServiceNotFoundException; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.util.List; -import reactor.core.publisher.Mono; - -public class Main { - - private static final String USE_AZURE_CLIENT = System.getenv("USE_AZURE_CLIENT"); - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); - - public static void main(String[] args) throws InterruptedException { - - Kernel kernel = buildKernel(); - - String text = """ - The users name is: Steven. - Steven has account number 012345612. - Steven was born in New York and their mother is Sally. - """.stripIndent(); - - System.out.println("=============================="); - System.out.println("Input text is: \n" + text); - - AnonymizedText result = kernel - .invokeAsync("redactor", "redact") - .withResultType(AnonymizedText.class) - .withArguments( - KernelArguments.builder() - .withVariable("input", text) - .build()) - .block() - .getResult(); - - System.out.println("=============================="); - System.out.println("Anonymised text is: \n" + result.getRedacted()); - - askQuestion(kernel, result, "Question: Where was the user born?").block(); - askQuestion(kernel, result, "Question: Who is the users mother?").block(); - - } - - private static Mono>> askQuestion( - Kernel kernel, - AnonymizedText anonymizedUserInfo, - String question) { - ChatHistory chat = formChatHistory(); - - chat.addUserMessage(anonymizedUserInfo.getRedacted()); - chat.addUserMessage(question); - - System.out.println("=============================="); - System.out.println("User Question: \n" + question); - - try { - return kernel - .getService(ChatCompletionService.class) - .getChatMessageContentsAsync(chat, kernel, - InvocationContext.builder() - .withPromptExecutionSettings( - PromptExecutionSettings.builder() - .withMaxTokens(2048) - .withTemperature(0.5) - .build()) - .build()) - .map(chatHistory -> { - String message = chatHistory.get(0).getContent(); - System.out.println("=============================="); - System.out.println( - "Anonymised response: \n" + message); - - System.out.println("=============================="); - System.out.println( - "Deanonymised response: \n" + anonymizedUserInfo.unredact(message)); - return chatHistory; - }); - - } catch (ServiceNotFoundException e) { - throw new RuntimeException(e); - } - } - - private static ChatHistory formChatHistory() { - ChatHistory chat = new ChatHistory(); - - chat.addSystemMessage( - """ - You answer questions about the provided information. - The following is an example of answering a question about a user. - - Information about the user: - The users name is PERSON100. - PERSON100 has long hair. - - Question: What does the users hair look like? - Answer: The user has long hair. - """.stripIndent()); - - return chat; - } - - private static Kernel buildKernel() { - OpenAIAsyncClient client; - - if (Boolean.parseBoolean(USE_AZURE_CLIENT)) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - ContextVariableTypes.addGlobalConverter(new AnonymizedTextConverter()); - - return Kernel - .builder() - .withAIService(ChatCompletionService.class, chat) - .withPlugin( - KernelPluginFactory.createFromObject( - new RedactorPlugin( - "http://presidio-analyzer:3000", - "http://presidio-anonymizer:3000"), - "redactor")) - .build(); - - } - -} diff --git a/samples/semantickernel-demos/sk-presidio-sample/src/main/resources/log4j2.xml b/samples/semantickernel-demos/sk-presidio-sample/src/main/resources/log4j2.xml deleted file mode 100644 index 50a638f0d..000000000 --- a/samples/semantickernel-demos/sk-presidio-sample/src/main/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/pom.xml b/samples/semantickernel-learn-resources/pom.xml deleted file mode 100644 index 8d5130b22..000000000 --- a/samples/semantickernel-learn-resources/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-learn-resources - jar - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - - com.microsoft.semantic-kernel - semantickernel-data-azureaisearch - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - - - com.microsoft.semantic-kernel - semantickernel-data-redis - - - com.microsoft.semantic-kernel - semantickernel-data-oracle - - - org.apache.logging.log4j - log4j-api - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.azure - azure-identity - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - com.microsoft.semantic-kernel - semantickernel-experimental - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.mysql - mysql-connector-j - 9.0.0 - compile - - - com.microsoft.semantic-kernel - semantickernel-data-postgres - compile - - - com.microsoft.semantic-kernel - semantickernel-api-data - compile - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - - - - diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/AIServices.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/AIServices.java deleted file mode 100644 index 09df9f874..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/AIServices.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; - -public class AIServices { - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String CHAT_MODEL_ID = System.getenv() - .getOrDefault("CHAT_MODEL_ID", "gpt-3.5-turbo"); - private static final String TEXT_MODEL_ID = System.getenv() - .getOrDefault("TEXT_MODEL_ID", "text-davinci-002"); - - public static void main(String[] args) { - System.out.println("======== AI Services ========"); - - OpenAIAsyncClient client = null; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(CHAT_MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - // - - // - TextGenerationService textGenerationService = TextGenerationService.builder() - .withModelId(TEXT_MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - // - - // - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withAIService(TextGenerationService.class, textGenerationService) - .build(); - // - - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/ConfiguringPrompts.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/ConfiguringPrompts.java deleted file mode 100644 index df05d8a49..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/ConfiguringPrompts.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import java.util.HashMap; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class ConfiguringPrompts { - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String CHAT_MODEL_ID = System.getenv() - .getOrDefault("CHAT_MODEL_ID", "gpt-3.5-turbo"); - - public static void main(String[] args) { - System.out.println("======== Configuring Prompts ========"); - - OpenAIAsyncClient client = null; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(CHAT_MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - // - - // - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .build(); - // - - // - KernelFunction chat = KernelFunction.createFromPrompt( - PromptTemplateConfig.builder() - .withName("Chat") - .withTemplate( - """ - {{ConversationSummaryPlugin.SummarizeConversation $history}} - User: {{$request}} - Assistant: - """.stripIndent()) - .addInputVariable(InputVariable.build( - "history", - String.class, - "The history of the conversation.", - null, - null, - false)) - .addInputVariable(InputVariable.build( - "request", - String.class, - "The user's request.", - null, - null, - true)) - .withExecutionSettings(new HashMap() { - { - put("gpt-3.5-turbo", PromptExecutionSettings.builder() - .withMaxTokens(1_000) - .withTemperature(0d) - .build()); - put("gpt-4", PromptExecutionSettings.builder() - .withModelId("gpt-4-1106-preview") - .withMaxTokens(8_000) - .withTemperature(0.3d) - .build()); - } - }) - .build()) - .build(); - // - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/CreatingFunctions.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/CreatingFunctions.java deleted file mode 100644 index ec3b9b951..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/CreatingFunctions.java +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.MathPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.util.Scanner; - -public class CreatingFunctions { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", - "gpt-35-turbo-2"); - - public static void main(String[] args) { - System.out.println("======== Prompts ========"); - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build()) - .withPlugin(KernelPluginFactory.createFromObject(new MathPlugin(), "MathPlugin")) - .build(); - - // Test the math plugin - var answer = kernel - .invokeAsync(kernel.getFunction("MathPlugin", "sqrt")) - .withArguments(KernelArguments - .builder() - .withVariable("number1", 12.0) - .build()) - .block(); - System.out.println("The square root of 12 is " + answer.getResult() + "."); - // - - // Create chat history - ChatCompletionService chat = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - System.out.println("Chat content:"); - System.out.println("------------------------"); - - // - ChatHistory history = new ChatHistory(); - - // Start the conversation - System.out.print("User > "); - Scanner scanner = new Scanner(System.in); - String userInput; - while (!(userInput = scanner.nextLine()).isEmpty()) { - history.addUserMessage(userInput); - - // Enable auto function calling - var invocationContext = InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .build(); - - // Get the response from the AI - var reply = chat.getChatMessageContentsAsync(history, kernel, invocationContext) - .block(); - - String message = CollectionUtil.getLastOrNull(reply).getContent(); - System.out.println("Assistant > " + message); - - // Add the message from the agent to the chat history - history.addAssistantMessage(message.toString()); - - // Get user input again - System.out.print("User > "); - } - // - } -} \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/FunctionsWithinPrompts.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/FunctionsWithinPrompts.java deleted file mode 100644 index de394835d..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/FunctionsWithinPrompts.java +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import java.util.Arrays; -import java.util.List; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; - -public class FunctionsWithinPrompts { - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - public static void main(String[] args) { - - System.out.println("======== Functions within Prompts ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - // - - // - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), "ConversationSummaryPlugin"); - // - - // - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin(plugin) - .build(); - // - - List choices = Arrays.asList("ContinueConversation", "EndConversation"); - - // Create few-shot examples - List fewShotExamples = Arrays.asList( - - new ChatHistory() { - { - addMessage(AuthorRole.USER, - "Can you send a very quick approval to the marketing team?"); - addMessage(AuthorRole.SYSTEM, "Intent:"); - addMessage(AuthorRole.ASSISTANT, "ContinueConversation"); - } - }, - new ChatHistory() { - { - addMessage(AuthorRole.USER, - "Can you send the full update to the marketing team?"); - addMessage(AuthorRole.SYSTEM, "Intent:"); - addMessage(AuthorRole.ASSISTANT, "EndConversation"); - } - }); - - // Create handlebars template for intent - // - KernelFunction getIntent = KernelFunction.createFromPrompt( - """ - Instructions: What is the intent of this request? - Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}. - Choices: {{choices}}. - - {{#each fewShotExamples}} - {{#each this}} - {{content}} - {{/each}} - {{/each}} - - {{ConversationSummaryPlugin-SummarizeConversation history}} - - {{request}} - Intent: - """) - .withTemplateFormat("handlebars") - .build(); - // - - // Create a Semantic Kernel template for chat - // - KernelFunction chat = KernelFunction.createFromPrompt( - """ - {{ConversationSummaryPlugin.SummarizeConversation $history}} - User: {{$request}} - Assistant: - """) - .build(); - // - - // Create chat history - ChatHistory history = new ChatHistory(); - - // Start the chat loop - // - while (true) { - // Get user input - System.console().printf("User > "); - String request = System.console().readLine(); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("request", request) - .withVariable("choices", choices) - .withVariable("history", history) - .withVariable("fewShotExamples", fewShotExamples) - .build(); - - // Invoke handlebars prompt - FunctionResult intent = kernel.invokeAsync(getIntent) - .withArguments(arguments) - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(true, - plugin.get("SummarizeConversation"))) - .block(); - - // End the chat if the intent is "Stop" - if ("EndConversation".equals(intent.getResult())) { - break; - } - - // Get chat response - FunctionResult chatResult = chat.invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withVariable("request", request) - .withVariable("history", history) - .build()) - .block(); - - String message = chatResult.getResult(); - System.console().printf("Assistant > %s\n", message); - - // Append to history - history.addUserMessage(request); - history.addAssistantMessage(message); - } - // - } - -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Plugin.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Plugin.java deleted file mode 100644 index c0ed21eb9..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Plugin.java +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.implementation.CollectionUtil; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.io.InputStream; -import java.util.Scanner; - -public class Plugin { - - public static InputStream INPUT = System.in; - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - public static void main(String[] args) { - System.out.println("======== Plugin ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - // - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - // - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new LightPlugin(), "LightPlugin"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin(plugin) - .build(); - // - - // - // Create chat history - var history = new ChatHistory(); - - // Start the conversation - System.out.print("User > "); - Scanner scanner = new Scanner(INPUT); - String userInput; - while (!(userInput = scanner.nextLine()).isEmpty()) { - // Add user input to history - history.addUserMessage(userInput); - - // Enable auto function calling - var invocationContext = InvocationContext.builder() - .withToolCallBehavior( - ToolCallBehavior.allowAllKernelFunctions(true)) - .build(); - - // Get the response from the AI - var result = chatCompletionService - .getChatMessageContentsAsync( - history, - kernel, - invocationContext) - .block(); - - String message = CollectionUtil.getLastOrNull(result).getContent(); - System.out.printf("Assistant > %s%n", message); - - // Add the message from the agent to the chat history - history.addAssistantMessage(message); - System.out.print("User > "); - } - // - } - - // - public static class LightPlugin { - - private boolean isOn = false; - - @DefineKernelFunction(name = "getState", description = "Gets the state of the light.'") - String getState() { - return isOn ? "on" : "off"; - } - - @DefineKernelFunction(name = "changeState", description = "Changes the state of the light.'") - public String changeState( - @KernelFunctionParameter(name = "newState", description = "The new state of the light, boolean true==on, false==off.", type = boolean.class) boolean newState) { - - this.isOn = newState; - String state = getState(); - - // Print the state to the console - System.out.printf("[Light is now %s]%n", state); - return state; - } - } - // -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Prompts.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Prompts.java deleted file mode 100644 index 20051eb86..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Prompts.java +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class Prompts { - - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", - "gpt-35-turbo-2"); - - public static void main(String[] args) { - System.out.println("======== Prompts ========"); - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - // - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build()) - .build(); - // - - // 0.0 Initial prompt - String request = "I want to send an email to the marketing team celebrating their recent milestone."; - String prompt = """ - What is the intent of this request? %s - """.formatted(request); - - // @formatter:off - /* - Uncomment this block to make this example interactive - // - System.out.println("Your request: "); - String request = new Scanner(System.in).nextLine(); - String prompt = """ - What is the intent of this request? %s - You can choose between SendEmail, SendMessage, CompleteTask, CreateDocument. - """.formatted(request); - // - */ - // @formatter:on - - System.out.println("0.0 Initial prompt"); - // - var result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - // - - // 1.0 Make the prompt more specific - ///////////////////////////////////////////////////////////////// - // - prompt = """ - What is the intent of this request? %s - You can choose between SendEmail, SendMessage, CompleteTask, CreateDocument. - """.formatted(request); - // - System.out.println("1.0 Make the prompt more specific"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 2.0 Add structure to the output with formatting - ///////////////////////////////////////////////////////////////// - // - prompt = """ - Instructions: What is the intent of this request? - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument. - User Input: %s - Intent: - """.formatted(request); - // - System.out.println("2.0 Add structure to the output with formatting"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 2.1 Add structure to the output with formatting (using Markdown and JSON) - ///////////////////////////////////////////////////////////////// - // - prompt = """ - ## Instructions - Provide the intent of the request using the following format: - - ```json - { - "intent": {intent} - } - ``` - - ## Choices - You can choose between the following intents: - - ```json - ["SendEmail", "SendMessage", "CompleteTask", "CreateDocument"] - ``` - - ## User Input - The user input is: - - ```json - { - "request": "%s" - } - ``` - - ## Intent - """.formatted(request); - // - System.out - .println("2.1 Add structure to the output with formatting (using Markdown and JSON)"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 3.0 Provide examples with few-shot prompting - ///////////////////////////////////////////////////////////////// - // - prompt = """ - Instructions: What is the intent of this request? - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument. - - User Input: Can you send a very quick approval to the marketing team? - Intent: SendMessage - - User Input: Can you send the full update to the marketing team? - Intent: SendEmail - - User Input: %s - Intent: - """.formatted(request); - // - System.out.println("3.0 Provide examples with few-shot prompting"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 4.0 Tell the AI what to do to avoid doing something wrong - ///////////////////////////////////////////////////////////////// - // - prompt = """ - Instructions: What is the intent of this request? - If you don't know the intent, don't guess; instead respond with "Unknown". - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument, Unknown. - - User Input: Can you send a very quick approval to the marketing team? - Intent: SendMessage - - User Input: Can you send the full update to the marketing team? - Intent: SendEmail - - User Input: %s - Intent: - """.formatted(request); - // - System.out.println("4.0 Tell the AI what to do to avoid doing something wrong"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 5.0 Provide context to the AI - ///////////////////////////////////////////////////////////////// - // - String history = "User input: I hate sending emails, no one ever reads them.\nAI response: I'm sorry to hear that. Messages may be a better way to communicate."; - prompt = """ - Instructions: What is the intent of this request? - If you don't know the intent, don't guess; instead respond with "Unknown". - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument, Unknown. - - User Input: Can you send a very quick approval to the marketing team? - Intent: SendMessage - - User Input: Can you send the full update to the marketing team? - Intent: SendEmail - - %s - User Input: %s - Intent: - """.formatted(history, request); - // - System.out.println("5.0 Provide context to the AI"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 6.0 Using message roles in chat completion prompts - ///////////////////////////////////////////////////////////////// - // - history = "I hate sending emails, no one ever reads them.\nI'm sorry to hear that. Messages may be a better way to communicate."; - prompt = """ - Instructions: What is the intent of this request? - If you don't know the intent, don't guess; instead respond with "Unknown". - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument, Unknown. - - Can you send a very quick approval to the marketing team? - Intent: - SendMessage - - Can you send the full update to the marketing team? - Intent: - SendEmail - - %s - %s - Intent: - """.formatted(history, request); - // - System.out.println("6.0 Using message roles in chat completion prompts"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - - // 7.0 Give your AI words of encouragement - // - history = "I hate sending emails, no one ever reads them.\nI'm sorry to hear that. Messages may be a better way to communicate."; - prompt = """ - Instructions: What is the intent of this request? - If you don't know the intent, don't guess; instead respond with "Unknown". - Choices: SendEmail, SendMessage, CompleteTask, CreateDocument, Unknown. - Bonus: You'll get $20 if you get this right. - - Can you send a very quick approval to the marketing team? - Intent: - SendMessage - - Can you send the full update to the marketing team? - Intent: - SendEmail - - %s - %s - Intent: - """.formatted(history, request); - // - System.out.println("7.0 Give your AI words of encouragement"); - result = kernel.invokePromptAsync(prompt).block().getResult(); - System.out.println(result); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/SerializingPrompts.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/SerializingPrompts.java deleted file mode 100644 index 233177e7d..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/SerializingPrompts.java +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.converters.CollectionVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionYaml; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; -import java.util.stream.Collectors; - -public class SerializingPrompts { - - public static InputStream INPUT = System.in; - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - private static final String PLUGINS_DIR = "samples/semantickernel-learn-resources/src/main/resources/Plugins"; - - public static void main(String[] args) throws IOException { - System.out.println("======== Serializing Prompts ========"); - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // Create few-shot examples - ChatHistory continueConversation = new ChatHistory(); - continueConversation.addMessage(AuthorRole.USER, - "Can you send a very quick approval to the marketing team?"); - continueConversation.addMessage(AuthorRole.SYSTEM, "Intent:"); - continueConversation.addMessage(AuthorRole.ASSISTANT, "ContinueConversation"); - ChatHistory endConversation = new ChatHistory(); - endConversation.addMessage(AuthorRole.USER, "Thats all"); - endConversation.addMessage(AuthorRole.SYSTEM, "Intent:"); - endConversation.addMessage(AuthorRole.ASSISTANT, "EndConversation"); - - List fewShotExamples = List.of(continueConversation, endConversation); - - // Customise the type converters toPromptString for ChatHistory to serialize the messages as "author: content" - CollectionVariableContextVariableTypeConverter collectionConverter = new CollectionVariableContextVariableTypeConverter( - "\n"); - - // - // Create Kernel - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build()) - .withPlugin(KernelPluginFactory.createFromObject(new ConversationSummaryPlugin(), - "ConversationSummaryPlugin")) - .build(); - - // Load prompts - var prompts = KernelPluginFactory.importPluginFromDirectory( - Path.of(PLUGINS_DIR), "Prompts", null); - - // Load prompt from YAML - // - var getIntent = KernelFunctionYaml.fromPromptYaml( - Files.readString(Path.of(PLUGINS_DIR, "Prompts", "getIntent.prompt.yaml")), - new HandlebarsPromptTemplateFactory()); - // - - // Create choices - List choices = Arrays.asList("ContinueConversation", "EndConversation"); - - // Create chat history - ChatHistory history = new ChatHistory(); - - // Start the chat loop - Scanner scanner = new Scanner(INPUT); - System.out.print("User > "); - String userInput; - while (!(userInput = scanner.nextLine()).isEmpty()) { - // Invoke handlebars prompt - - String historyString = history.getMessages() - .stream() - .map(m -> m.getAuthorRole() + " > " + m.getContent()) - .collect(Collectors.joining("\n")); - - // - var intent = kernel.invokeAsync(getIntent) - .withArguments(KernelArguments.builder() - .withVariable("request", userInput) - .withVariable("choices", choices) - .withVariable("history", historyString) - .withVariable("fewShotExamples", fewShotExamples, collectionConverter) - .build()) - .block(); - // - - // End the chat if the intent is "Stop" - if (intent.getResult().equals("EndConversation")) { - break; - } - - var reply = kernel.invokeAsync(prompts.get("Chat")) - .withArguments(KernelArguments.builder() - .withVariable("request", userInput) - .withVariable("history", - String.join("\n", - history.getMessages().stream() - .map(m -> m.getAuthorRole() + " > " + m.getContent()).toList())) - .build()) - .withResultType(String.class) - .block().getResult(); - - System.out.println("Assistant > " + reply); - - // Append to history - history.addUserMessage(userInput); - history.addAssistantMessage(reply); - - // Get user input again - System.out.print("User > "); - } - // - } -} \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Templates.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Templates.java deleted file mode 100644 index b830cd29f..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/Templates.java +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; -import java.util.stream.Collectors; - -public class Templates { - - public static InputStream INPUT = System.in; - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - public static void main(String[] args) { - System.out.println("======== Templates ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // Customise the type converters toPromptString for ChatHistory to serialize the messages as "author: content" - ContextVariableTypeConverter chatHistoryType = ContextVariableTypeConverter - .builder(ChatHistory.class) - .proxyGlobalType() - .toPromptString(history -> { - return history.getMessages() - .stream() - .map(message -> String.format("%s: %s", - message.getAuthorRole(), - message.getContent())) - .collect(Collectors.joining("\n")); - }) - .build(); - - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new ConversationSummaryPlugin(), "ConversationSummaryPlugin"); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin(plugin) - .build(); - - // - KernelFunction chat = KernelFunctionFromPrompt.createFromPrompt(""" - {{$history}} - user: {{$request}} - assistant:""") - .build(); - // - - // - List choices = Arrays.asList("ContinueConversation", "EndConversation"); - - // Create few-shot examples - List fewShotExamples = Arrays.asList( - - new ChatHistory() { - { - addMessage(AuthorRole.USER, - "Can you send a very quick approval to the marketing team?"); - addMessage(AuthorRole.SYSTEM, "Intent:"); - addMessage(AuthorRole.ASSISTANT, "ContinueConversation"); - } - }, - new ChatHistory() { - { - addMessage(AuthorRole.USER, "Thanks, I'm done for now"); - addMessage(AuthorRole.SYSTEM, "Intent:"); - addMessage(AuthorRole.ASSISTANT, "EndConversation"); - } - }); - // - - // - // Create handlebars template for intent - KernelFunction getIntent = KernelFunction.createFromPrompt( - """ - Instructions: What is the intent of this request? - Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}. - Choices: {{choices}}. - - {{#each fewShotExamples}} - {{#each this}} - {{content}} - {{/each}} - {{/each}} - - {{#each chatHistory}} - {{content}} - {{/each}} - - {{request}} - Intent: - """) - .withTemplateFormat("handlebars") - .build(); - // - - Scanner scanner = new Scanner(INPUT); - // - // Create chat history - ChatHistory history = new ChatHistory(); - - // Start the chat loop - while (true) { - // - // Get user input - System.out.print("User > "); - String request = scanner.nextLine(); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("request", request) - .withVariable("choices", choices) - .withVariable("chatHistory", history) - .withVariable("fewShotExamples", fewShotExamples) - .build(); - // - - // - // Invoke handlebars prompt - FunctionResult intent = kernel.invokeAsync(getIntent) - .withArguments(arguments) - .withToolCallBehavior( - ToolCallBehavior.allowOnlyKernelFunctions(true, - plugin.get("SummarizeConversation"))) - .block(); - // - - // End the chat if the intent is "Stop" - if ("EndConversation".equals(intent.getResult())) { - break; - } - - // Get chat response - FunctionResult chatResult = chat.invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withVariable("request", request) - .withVariable("history", history, chatHistoryType) - .build()) - .block(); - - String message = chatResult.getResult(); - System.out.printf("Assistant > %s\n", message); - - // Append to history - history.addUserMessage(request); - history.addAssistantMessage(message); - } - // - } - -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/UsingTheKernel.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/UsingTheKernel.java deleted file mode 100644 index ebb0e4979..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/UsingTheKernel.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.samples.plugins.MathPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class UsingTheKernel { - - // CLIENT_KEY is for an OpenAI client - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - - // AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client - // CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-3.5-turbo"); - - public static void main(String[] args) { - System.out.println("======== UsingTheKernel ========"); - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) { - // - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - // - } else if (CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } else { - System.out.println("No client key found"); - return; - } - - // - - ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder() - .withModelId(MODEL_ID) - .withOpenAIAsyncClient(client) - .build(); - - KernelPlugin mathPlugin = KernelPluginFactory.createFromObject( - new MathPlugin(), "MathPlugin"); - - var poemPlugin = KernelPluginFactory.importPluginFromResourcesDirectory( - "Plugins", - "WriterPlugin", - "ShortPoem", - null, - String.class); - - Kernel kernel = Kernel.builder() - .withAIService(ChatCompletionService.class, chatCompletionService) - .withPlugin(mathPlugin) - .withPlugin(poemPlugin) - .build(); - - // - - // - var result = poemPlugin.get("ShortPoem") - .invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withInput("The cat sat on a mat") - .build()) - .withResultType(String.class) - .block(); - System.out.println(result.getResult()); - // - - // - var root = mathPlugin.get("sqrt") - .invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withInput(12) - .build()) - .withResultType(Double.class) - .block(); - System.out.println("Square root of 12 is: " + root.getResult()); - // - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Hotel.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Hotel.java deleted file mode 100644 index 6fff7664f..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Hotel.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.index; - -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import java.util.Collections; -import java.util.List; - -public class Hotel { - @VectorStoreRecordKey - private String hotelId; - - @VectorStoreRecordData(isFilterable = true) - private String name; - - @VectorStoreRecordData(isFullTextSearchable = true) - private String description; - - @VectorStoreRecordVector(dimensions = 4, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private List descriptionEmbedding; - - @VectorStoreRecordData(isFilterable = true) - private List tags; - - public Hotel() { - } - - public Hotel(String hotelId, String name, String description, List descriptionEmbedding, - List tags) { - this.hotelId = hotelId; - this.name = name; - this.description = description; - this.descriptionEmbedding = Collections.unmodifiableList(descriptionEmbedding); - this.tags = Collections.unmodifiableList(tags); - } - - public String getHotelId() { - return hotelId; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public List getDescriptionEmbedding() { - return descriptionEmbedding; - } - - public List getTags() { - return tags; - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Main.java deleted file mode 100644 index 414c9be8c..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/index/Main.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.index; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import org.postgresql.ds.PGSimpleDataSource; -import reactor.core.publisher.Mono; - -import java.util.List; - -public class Main { - public static void main(String[] args) { - // Create a PostgreSQL data source - PGSimpleDataSource dataSource = new PGSimpleDataSource(); - dataSource.setUrl("jdbc:postgresql://localhost:5432/sk"); - dataSource.setUser("postgres"); - dataSource.setPassword("root"); - - // Create a JDBC vector store - var vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions( - JDBCVectorStoreOptions.builder() - .withQueryProvider(PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build()) - .build()) - .build(); - - // Get a collection from the vector store - var collection = vectorStore.getCollection("skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - // Create the collection if it doesn't exist yet. - collection.createCollectionAsync().block(); - - // Upsert a record. - var description = "A place where everyone can be happy"; - var hotelId = "1"; - var hotel = new Hotel( - hotelId, - "Hotel Happy", - description, - generateEmbeddingsAsync(description).block(), - List.of("luxury", "pool")); - - collection.upsertAsync(hotel, null).block(); - - // Retrieve the upserted record. - var retrievedHotel = collection.getAsync(hotelId, null).block(); - - // Generate a vector for your search text, using your chosen embedding generation implementation. - // Just showing a placeholder method here for brevity. - var searchVector = generateEmbeddingsAsync( - "I'm looking for a hotel where customer happiness is the priority.").block(); - - // Do the search. - var searchResult = collection.searchAsync(searchVector, VectorSearchOptions.builder() - .withTop(1).build()).block(); - - Hotel record = searchResult.getResults().get(0).getRecord(); - System.out.printf("Found hotel description: %s\n", record.getDescription()); - } - - private static Mono> generateEmbeddingsAsync(String text) { - return Mono.just(List.of(1.0f, 2.0f, 3.0f, 4.0f)); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/recorddefinition/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/recorddefinition/Main.java deleted file mode 100644 index cf6ad56ba..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/recorddefinition/Main.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.recorddefinition; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.definition.*; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; -import org.postgresql.ds.PGSimpleDataSource; - -import java.util.Arrays; -import java.util.List; - -public class Main { - public static void main(String[] args) { - // Create a PostgreSQL data source - PGSimpleDataSource dataSource = new PGSimpleDataSource(); - dataSource.setUrl("jdbc:postgresql://localhost:5432/sk"); - dataSource.setUser("postgres"); - dataSource.setPassword("root"); - - // Create a JDBC vector store - var vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions( - JDBCVectorStoreOptions.builder() - .withQueryProvider(PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build()) - .build()) - .build(); - - var hotelDefinition = VectorStoreRecordDefinition.fromFields( - Arrays.asList( - VectorStoreRecordKeyField.builder().withName("hotelId").withFieldType(String.class) - .build(), - VectorStoreRecordDataField.builder() - .withName("name") - .withFieldType(String.class) - .isFilterable(true).build(), - VectorStoreRecordDataField.builder() - .withName("description") - .withFieldType(String.class) - .isFullTextSearchable(true).build(), - VectorStoreRecordVectorField.builder().withName("descriptionEmbedding") - .withDimensions(4) - .withIndexKind(IndexKind.HNSW) - .withDistanceFunction(DistanceFunction.COSINE_DISTANCE) - .withFieldType(List.class).build())); - - var collection = vectorStore.getCollection("skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordDefinition(hotelDefinition) - .withRecordClass(Hotel.class) - .build()); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/hotels/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/hotels/Main.java deleted file mode 100644 index a53562442..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/hotels/Main.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorsearch.hotels; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; -import org.postgresql.ds.PGSimpleDataSource; -import reactor.core.publisher.Mono; - -import java.util.List; - -public class Main { - public static void main(String[] args) { - // Configure the data source - PGSimpleDataSource dataSource = new PGSimpleDataSource(); - dataSource.setUrl("jdbc:postgresql://localhost:5432/sk"); - dataSource.setUser("postgres"); - dataSource.setPassword("root"); - - // Create a JDBC vector store and choose an existing collection that already contains records. - var vectorStore = new JDBCVectorStore(dataSource, JDBCVectorStoreOptions.builder() - .withQueryProvider(PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build()) - .build()); - var collection = vectorStore.getCollection("skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - // Generate a vector for your search text, using your chosen embedding generation implementation. - // Just showing a placeholder method here for brevity. - var searchVector = generateEmbeddingsAsync( - "I'm looking for a hotel where customer happiness is the priority.").block(); - - // Do the search, passing an options object with a Top value to limit results to the single top match. - var searchResult = collection.searchAsync(searchVector, VectorSearchOptions.builder() - .withTop(1).build()).block(); - - // Inspect the returned hotel. - Hotel hotel = searchResult.getResults().get(0).getRecord(); - System.out.printf("Found hotel description: %s\n", hotel.getDescription()); - } - - private static Mono> generateEmbeddingsAsync(String text) { - return Mono.just(List.of(1.0f, 2.0f, 3.0f, 4.0f)); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/products/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/products/Main.java deleted file mode 100644 index f96593284..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorsearch/products/Main.java +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorsearch.products; - -import com.microsoft.semantickernel.data.VolatileVectorStore; -import com.microsoft.semantickernel.data.VolatileVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import reactor.core.publisher.Mono; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class Main { - public static void main(String[] args) { - // Build a query provider - var vectorStore = new VolatileVectorStore(); - var collection = vectorStore.getCollection("skproducts", - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Product.class) - .build()); - collection.createCollectionIfNotExistsAsync().block(); - var vector = generateEmbeddingsAsync().block(); - collection.upsertAsync( - new Product("1", "Product 1", List.of("Feature 1", "Feature 2"), vector, vector), null) - .block(); - - withVectorFieldName(collection); - withTopAndSkip(collection); - withIncludeVectors(collection); - withVectorSearchFilter(); - } - - public static void withVectorFieldName( - VectorStoreRecordCollection collection) { - // Create the vector search options and indicate that we want to search the FeatureListEmbedding field. - var searchOptions = VectorSearchOptions.builder() - .withVectorFieldName("featureListEmbedding") - .build(); - - // Generate a vector for your search text, using the embedding model of your choice - var searchVector = generateEmbeddingsAsync().block(); - - // Do the search - var searchResult = collection.searchAsync(searchVector, searchOptions).block(); - } - - public static void withTopAndSkip(VectorStoreRecordCollection collection) { - // Create the vector search options and indicate that we want to skip the first 40 results and then get the next 20. - var searchOptions = VectorSearchOptions.builder() - .withTop(20) - .withSkip(40) - .build(); - - // Generate a vector for your search text, using the embedding model of your choice - var searchVector = generateEmbeddingsAsync().block(); - - // Do the search - var searchResult = collection.searchAsync(searchVector, searchOptions).block(); - } - - public static void withIncludeVectors(VectorStoreRecordCollection collection) { - // Create the vector search options and indicate that we want to include vectors in the search results. - var searchOptions = VectorSearchOptions.builder() - .withIncludeVectors(true) - .build(); - - // Generate a vector for your search text, using the embedding model of your choice - var searchVector = generateEmbeddingsAsync().block(); - - // Do the search - var searchResult = collection.searchAsync(searchVector, searchOptions).block(); - } - - public static void withVectorSearchFilter() { - // Build a query provider - var vectorStore = new VolatileVectorStore(); - var collection = vectorStore.getCollection("skglossary", - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Glossary.class) - .build()); - collection.createCollectionIfNotExistsAsync().block(); - var vector = generateEmbeddingsAsync().block(); - collection.upsertAsync(new Glossary("1", "External Definitions", List.of("memory"), - "Memory", "The power of the mind to remember things", vector), null).block(); - - // Filter where category == 'External Definitions' and tags contain 'memory'. - var filter = VectorSearchFilter.builder() - .equalTo("category", "External Definitions") - .anyTagEqualTo("tags", "memory") - .build(); - - // Create the vector search options and indicate that we want to filter the search results by a specific field. - var searchOptions = VectorSearchOptions.builder() - .withVectorSearchFilter(filter) - .build(); - - // Generate a vector for your search text, using the embedding model of your choice - var searchVector = generateEmbeddingsAsync().block(); - - // Do the search - var searchResult = collection.searchAsync(searchVector, searchOptions).block(); - } - - public static class Product { - @VectorStoreRecordKey - private String key; - - @VectorStoreRecordData - private String description; - - @VectorStoreRecordData - private List featureList; - - @VectorStoreRecordVector(dimensions = 1536) - public List descriptionEmbedding; - - @VectorStoreRecordVector(dimensions = 1536) - public List featureListEmbedding; - - public Product() { - } - - public Product(String key, String description, List featureList, - List descriptionEmbedding, List featureListEmbedding) { - this.key = key; - this.description = description; - this.featureList = featureList; - this.descriptionEmbedding = Collections.unmodifiableList(descriptionEmbedding); - this.featureListEmbedding = Collections.unmodifiableList(featureListEmbedding); - } - - public String getKey() { - return key; - } - - public String getDescription() { - return description; - } - - public List getFeatureList() { - return featureList; - } - - public List getDescriptionEmbedding() { - return descriptionEmbedding; - } - - public List getFeatureListEmbedding() { - return featureListEmbedding; - } - } - - public static class Glossary { - @VectorStoreRecordKey - private String key; - - @VectorStoreRecordData(isFilterable = true) - private String category; - - @VectorStoreRecordData(isFilterable = true) - private List tags; - - @VectorStoreRecordData - private String term; - - @VectorStoreRecordData - private String definition; - - @VectorStoreRecordVector(dimensions = 1536) - private List definitionEmbedding; - - public Glossary() { - } - - public Glossary(String key, String category, List tags, String term, - String definition, List definitionEmbedding) { - this.key = key; - this.category = category; - this.tags = tags; - this.term = term; - this.definition = definition; - this.definitionEmbedding = Collections.unmodifiableList(definitionEmbedding); - } - - public String getKey() { - return key; - } - - public String getCategory() { - return category; - } - - public List getTags() { - return tags; - } - - public String getTerm() { - return term; - } - - public String getDefinition() { - return definition; - } - - public List getDefinitionEmbedding() { - return definitionEmbedding; - } - } - - private static Mono> generateEmbeddingsAsync() { - return Mono.just(new ArrayList<>(Collections.nCopies(1536, 1.0f))); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/azureaisearch/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/azureaisearch/Main.java deleted file mode 100644 index 89ce88ea3..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/azureaisearch/Main.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.azureaisearch; - -import com.azure.core.credential.AzureKeyCredential; -import com.azure.search.documents.indexes.SearchIndexClientBuilder; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStore; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStoreOptions; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.azureaisearch.AzureAISearchVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; - -public class Main { - public static void main(String[] args) { - // Build the Azure AI Search client - var searchClient = new SearchIndexClientBuilder() - .endpoint("https://.search.windows.net") - .credential(new AzureKeyCredential("")) - .buildAsyncClient(); - - // Build an Azure AI Search Vector Store - var vectorStore = AzureAISearchVectorStore.builder() - .withSearchIndexAsyncClient(searchClient) - .withOptions(new AzureAISearchVectorStoreOptions()) - .build(); - - var collection = new AzureAISearchVectorStoreRecordCollection<>(searchClient, "skhotels", - AzureAISearchVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/inmemory/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/inmemory/Main.java deleted file mode 100644 index fff6e115a..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/inmemory/Main.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.inmemory; - -import com.microsoft.semantickernel.data.VolatileVectorStore; -import com.microsoft.semantickernel.data.VolatileVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.VolatileVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; - -public class Main { - public static void main(String[] args) { - // Build an Azure AI Search Vector Store - var vectorStore = new VolatileVectorStore(); - - var collection = new VolatileVectorStoreRecordCollection<>("skhotels", - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/jdbc/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/jdbc/Main.java deleted file mode 100644 index 8b7bc1257..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/jdbc/Main.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.jdbc; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollection; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.postgres.PostgreSQLVectorStoreQueryProvider; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; -import org.postgresql.ds.PGSimpleDataSource; - -public class Main { - public static void main(String[] args) { - // Configure the data source - PGSimpleDataSource dataSource = new PGSimpleDataSource(); - dataSource.setUrl("jdbc:postgresql://localhost:5432/sk"); - dataSource.setUser("postgres"); - dataSource.setPassword("root"); - - // Build a query provider - // Other available query providers are MySQLVectorStoreQueryProvider, SQLiteVectorStoreQueryProvider - // and HSQDBVectorStoreQueryProvider - var queryProvider = PostgreSQLVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - - // Build a vector store - var vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - var collection = new JDBCVectorStoreRecordCollection<>( - dataSource, - "skhotels", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Book.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Book.java deleted file mode 100644 index 77b034bf4..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Book.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.oracle; - -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import java.util.List; - -public class Book { - - public Book() { - } - - public Book(String isbn, String title, String author, int pages, - List tags, String summary, List summaryEmbedding) { - this.isbn = isbn; - this.title = title; - this.author = author; - this.pages = pages; - this.tags = tags; - this.summary = summary; - this.summaryEmbedding = summaryEmbedding; - } - - @VectorStoreRecordKey - private String isbn; - - @VectorStoreRecordData(isFilterable = true) - private String title; - - @VectorStoreRecordData(isFilterable = true) - private String author; - - @VectorStoreRecordData - private int pages; - - @VectorStoreRecordData(isFilterable = true) - private List tags; - - @VectorStoreRecordData(isFilterable = true, isFullTextSearchable = true) - private String summary; - - @VectorStoreRecordVector(dimensions = 2) - private List summaryEmbedding; - - public String getIsbn() { - return isbn; - } - - public String getTitle() { - return title; - } - - public String getAuthor() { - return author; - } - - public int getPages() { - return pages; - } - - public List getTags() { - return tags; - } - - public String getSummary() { - return summary; - } - - public List getSummaryEmbedding() { - return summaryEmbedding; - } - - public void setIsbn(String isbn) { - this.isbn = isbn; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setAuthor(String author) { - this.author = author; - } - - public void setPages(int pages) { - this.pages = pages; - } - - public void setTags(List tags) { - this.tags = tags; - } - - public void setSummaryEmbedding(List summaryEmbedding) { - this.summaryEmbedding = summaryEmbedding; - } - - public void setSummary(String summary) { - this.summary = summary; - } -} \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Main.java deleted file mode 100644 index c03f3eb30..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/oracle/Main.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - ** Oracle Database Vector Store Connector for Semantic Kernel (Java) - ** - ** Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. - ** - ** The MIT License (MIT) - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to - ** deal in the Software without restriction, including without limitation the - ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - ** sell copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - ** IN THE SOFTWARE. - */ -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.oracle; - -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.jdbc.oracle.OracleVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import oracle.jdbc.datasource.impl.OracleDataSource; -import reactor.core.publisher.Mono; - -public class Main { - public static void main(String[] args) throws SQLException { - - // Configure the data source - OracleDataSource dataSource = new OracleDataSource(); - dataSource.setURL("jdbc:oracle:thin:@localhost:1521/FREEPDB1"); - dataSource.setUser("scott"); - dataSource.setPassword("tiger"); - - // Build a query provider - OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider.builder() - .withDataSource(dataSource) - .build(); - - // Build a vector store - JDBCVectorStore vectorStore = JDBCVectorStore.builder() - .withDataSource(dataSource) - .withOptions(JDBCVectorStoreOptions.builder() - .withQueryProvider(queryProvider) - .build()) - .build(); - - VectorStoreRecordCollection collection = vectorStore.getCollection( - "books", - JDBCVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Book.class) - .build()); - - // Create the collection if it doesn't exist yet. - collection.createCollectionIfNotExistsAsync().block(); - - collection.upsertBatchAsync(books, null).block(); - - // Retrieve the upserted record. - Book retrievedBook = collection.getAsync("2", null).block(); - - System.out.println(retrievedBook.getAuthor()); - - // Generate a vector for your search text, using your chosen embedding generation implementation. - // Just showing a placeholder method here for brevity. - List searchVector = generateEmbeddingsAsync( - "I'm looking for a horror book.").block(); - - // Do the search. - VectorSearchResults searchResult = collection.searchAsync( - searchVector, VectorSearchOptions.builder().withTop(1).build()).block(); - - retrievedBook = searchResult.getResults().get(0).getRecord(); - System.out.println("Found Book: " + retrievedBook.getIsbn()); - - } - - static List books = Arrays.asList( - new Book("1", "one", "sking", 0, null, "horror", List.of(1f, 1f)), - new Book("2", "two", "squeen", 0, null, "non-fiction", List.of(-1f, -1f))); - - private static Mono> generateEmbeddingsAsync(String text) { - return Mono.just(List.of(-0.1f, -0.1f)); - } - -} \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/redis/Main.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/redis/Main.java deleted file mode 100644 index 418c587c9..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/documentationexamples/data/vectorstores/redis/Main.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.documentationexamples.data.vectorstores.redis; - -import com.microsoft.semantickernel.data.redis.RedisJsonVectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.redis.RedisStorageType; -import com.microsoft.semantickernel.data.redis.RedisVectorStore; -import com.microsoft.semantickernel.data.redis.RedisVectorStoreOptions; -import com.microsoft.semantickernel.samples.documentationexamples.data.index.Hotel; -import redis.clients.jedis.JedisPooled; - -public class Main { - public static void main(String[] args) { - JedisPooled jedis = new JedisPooled(""); - - // Build a Redis Vector Store - // Available storage types are JSON and HASHSET. Default is JSON. - var vectorStore = RedisVectorStore.builder() - .withClient(jedis) - .withOptions( - RedisVectorStoreOptions.builder() - .withStorageType(RedisStorageType.HASH_SET).build()) - .build(); - - var collection = vectorStore.getCollection("skhotels", - RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - - collection = vectorStore.getCollection("skhotels", - RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withPrefixCollectionName(false) - .build()); - - collection.getAsync("myprefix_h1", null).block(); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java deleted file mode 100644 index 0a224c2fd..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/ConversationSummaryPlugin.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.text.TextChunker; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import java.util.List; - -///

-/// Semantic plugin that enables conversations summarization. -/// -public class ConversationSummaryPlugin { - - /// - /// The max tokens to process in a single prompt function call. - /// - private static final int MaxTokens = 1024; - - private KernelFunction summarizeConversationFunction; - private KernelFunction conversationActionItemsFunction; - private KernelFunction conversationTopicsFunction; - - /// - /// Initializes a new instance of the class. - /// - public ConversationSummaryPlugin() { - PromptExecutionSettings settings = PromptExecutionSettings.builder() - .withMaxTokens(MaxTokens) - .withTemperature(0.1) - .withTopP(0.5) - .build(); - - this.summarizeConversationFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.SummarizeConversationDefinition) - .withDefaultExecutionSettings(settings) - .withName("summarizeConversation") - .withDescription( - "Given a section of a conversation transcript, summarize the part of the conversation.") - .build(); - - this.conversationActionItemsFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.GetConversationActionItemsDefinition) - .withDefaultExecutionSettings(settings) - .withName("conversationActionItems") - .withDescription("Given a section of a conversation transcript, identify action items.") - .build(); - - this.conversationTopicsFunction = KernelFunction - .createFromPrompt(PromptFunctionConstants.GetConversationTopicsDefinition) - .withDefaultExecutionSettings(settings) - .withName("conversationTopics") - .withDescription( - "Analyze a conversation transcript and extract key topics worth remembering.") - .build(); - } - - private static Mono processAsync(KernelFunction func, String input, - Kernel kernel) { - List lines = TextChunker.splitPlainTextLines(input, MaxTokens); - List paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens); - - return Flux.fromIterable(paragraphs) - .concatMap(paragraph -> { - // The first parameter is the input text. - return func.invokeAsync(kernel) - .withArguments( - KernelArguments.builder() - .withInput(paragraph) - .build()) - .withResultType( - ContextVariableTypes.getGlobalVariableTypeForClass(String.class)); - }) - .reduce("", (acc, next) -> { - return acc + "\n" + next.getResult(); - }); - } - - /// - /// Given a long conversation transcript, summarize the conversation. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, summarize the conversation.", name = "SummarizeConversation", returnType = "java.lang.String") - public Mono SummarizeConversationAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.summarizeConversationFunction, input, kernel); - } - - /// - /// Given a long conversation transcript, identify action items. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, identify action items.", name = "GetConversationActionItems", returnType = "java.lang.String") - public Mono GetConversationActionItemsAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.conversationActionItemsFunction, input, kernel); - } - - /// - /// Given a long conversation transcript, identify topics. - /// - /// A long conversation transcript. - /// The containing services, plugins, and other state for use throughout the operation. - @DefineKernelFunction(description = "Given a long conversation transcript, identify topics worth remembering.", name = "GetConversationTopics", returnType = "java.lang.String") - - public Mono GetConversationTopicsAsync( - @KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input, - Kernel kernel) { - return processAsync(this.conversationTopicsFunction, input, kernel); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java deleted file mode 100644 index 1f9a7ce34..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/MathPlugin.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -// -public class MathPlugin { - // - - // - @DefineKernelFunction(name = "sqrt", description = "Take the square root of a number") - public static double sqrt( - @KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) { - return Math.sqrt(number1); - } - // - - @DefineKernelFunction(name = "add", description = "Add two numbers") - public static double add( - @KernelFunctionParameter(name = "number1", description = "The first number to add", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to add", type = double.class) double number2) { - return number1 + number2; - } - - @DefineKernelFunction(name = "subtract", description = "Subtract two numbers") - public static double subtract( - @KernelFunctionParameter(name = "number1", description = "The first number to subtract from", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to subtract away", type = double.class) double number2) { - return number1 - number2; - } - - @DefineKernelFunction(name = "multiply", description = "Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.") - public static double multiply( - @KernelFunctionParameter(name = "number1", description = "The first number to multiply", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to multiply", type = double.class) double number2) { - return number1 * number2; - } - - @DefineKernelFunction(name = "divide", description = "Divide two numbers") - public static double divide( - @KernelFunctionParameter(name = "number1", description = "The first number to divide from", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The second number to divide by", type = double.class) double number2) { - return number1 / number2; - } - - @DefineKernelFunction(name = "power", description = "Raise a number to a power") - public static double power( - @KernelFunctionParameter(name = "number1", description = "The number to raise", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The power to raise the number to", type = double.class) double number2) { - return Math.pow(number1, number2); - } - - @DefineKernelFunction(name = "log", description = "Take the log of a number") - public static double log( - @KernelFunctionParameter(name = "number1", description = "The number to take the log of", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The base of the log", type = double.class) double number2) { - return Math.log(number1) / Math.log(number2); - } - - @DefineKernelFunction(name = "round", description = "Round a number to the target number of decimal places") - public static double round( - @KernelFunctionParameter(name = "number1", description = "The number to round", type = double.class) double number1, - @KernelFunctionParameter(name = "number2", description = "The number of decimal places to round to", type = double.class) int number2) { - return Math.round(number1 * Math.pow(10, number2)) / Math.pow(10, number2); - } - - @DefineKernelFunction(name = "abs", description = "Take the absolute value of a number") - public static double abs( - @KernelFunctionParameter(name = "number1", description = "The number to take the absolute value of", type = double.class) double number1) { - return Math.abs(number1); - } - - @DefineKernelFunction(name = "floor", description = "Take the floor of a number") - public static double floor( - @KernelFunctionParameter(name = "number1", description = "The number to take the floor of", type = double.class) double number1) { - return Math.floor(number1); - } - - @DefineKernelFunction(name = "ceiling", description = "Take the ceiling of a number") - public static double ceiling( - @KernelFunctionParameter(name = "number1", description = "The number to take the ceiling of", type = double.class) double number1) { - return Math.ceil(number1); - } - - @DefineKernelFunction(name = "sin", description = "Take the sine of a number") - public static double sin( - @KernelFunctionParameter(name = "number1", description = "The number to take the sine of", type = double.class) double number1) { - return Math.sin(number1); - } - - @DefineKernelFunction(name = "cos", description = "Take the cosine of a number") - public static double cos( - @KernelFunctionParameter(name = "number1", description = "The number to take the cosine of", type = double.class) double number1) { - return Math.cos(number1); - } - - @DefineKernelFunction(name = "tan", description = "Take the tangent of a number") - public static double tan( - @KernelFunctionParameter(name = "number1", description = "The number to take the tangent of", type = double.class) double number1) { - return Math.tan(number1); - } - - @DefineKernelFunction(name = "asin", description = "Take the arcsine of a number") - public static double asin( - @KernelFunctionParameter(name = "number1", description = "The number to take the arcsine of", type = double.class) double number1) { - return Math.asin(number1); - } - - @DefineKernelFunction(name = "acos", description = "Take the arccosine of a number") - public static double acos( - @KernelFunctionParameter(name = "number1", description = "The number to take the arccosine of", type = double.class) double number1) { - return Math.acos(number1); - } - - @DefineKernelFunction(name = "atan", description = "Take the arctangent of a number") - public static double atan( - @KernelFunctionParameter(name = "number1", description = "The number to take the arctangent of", type = double.class) double number1) { - return Math.atan(number1); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java deleted file mode 100644 index 22c51f383..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/PromptFunctionConstants.java +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins; - -public class PromptFunctionConstants { - - public static final String SummarizeConversationDefinition = """ - BEGIN CONTENT TO SUMMARIZE: - {{$INPUT}} - - END CONTENT TO SUMMARIZE. - - Summarize the conversation in 'CONTENT TO SUMMARIZE', identifying main points of discussion and any conclusions that were reached. - Do not incorporate other general knowledge. - Summary is in plain text, in complete sentences, with no markup or tags. - - BEGIN SUMMARY: - """ - .stripIndent(); - - public static final String GetConversationActionItemsDefinition = """ - You are an action item extractor. You will be given chat history and need to make note of action items mentioned in the chat. - Extract action items from the content if there are any. If there are no action, return nothing. If a single field is missing, use an empty string. - Return the action items in json. - - Possible statuses for action items are: Open, Closed, In Progress. - - EXAMPLE INPUT WITH ACTION ITEMS: - - John Doe said: "I will record a demo for the new feature by Friday" - I said: "Great, thanks John. We may not use all of it but it's good to get it out there." - - EXAMPLE OUTPUT: - { - "actionItems": [ - { - "owner": "John Doe", - "actionItem": "Record a demo for the new feature", - "dueDate": "Friday", - "status": "Open", - "notes": "" - } - ] - } - - EXAMPLE INPUT WITHOUT ACTION ITEMS: - - John Doe said: "Hey I'm going to the store, do you need anything?" - I said: "No thanks, I'm good." - - EXAMPLE OUTPUT: - { - "action_items": [] - } - - CONTENT STARTS HERE. - - {{$INPUT}} - - CONTENT STOPS HERE. - - OUTPUT: - """ - .stripIndent(); - - public static final String GetConversationTopicsDefinition = """ - Analyze the following extract taken from a conversation transcript and extract key topics. - - Topics only worth remembering. - - Be brief. Short phrases. - - Can use broken English. - - Conciseness is very important. - - Topics can include names of memories you want to recall. - - NO LONG SENTENCES. SHORT PHRASES. - - Return in JSON - [Input] - My name is Macbeth. I used to be King of Scotland, but I died. My wife's name is Lady Macbeth and we were married for 15 years. We had no children. Our beloved dog Toby McDuff was a famous hunter of rats in the forest. - My tragic story was immortalized by Shakespeare in a play. - [Output] - { - "topics": [ - "Macbeth", - "King of Scotland", - "Lady Macbeth", - "Dog", - "Toby McDuff", - "Shakespeare", - "Play", - "Tragedy" - ] - } - +++++ - [Input] - {{$INPUT}} - [Output]""" - .stripIndent(); -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java deleted file mode 100644 index 0f8065ee1..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubModel.java +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.github; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; - -public abstract class GitHubModel { - public final static ObjectMapper objectMapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - @Override - public String toString() { - try { - return objectMapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - public static class User extends GitHubModel { - @JsonProperty("login") - private String login; - @JsonProperty("id") - private long id; - @JsonProperty("name") - private String name; - @JsonProperty("company") - private String company; - @JsonProperty("html_url") - private String url; - - @JsonCreator - public User(@JsonProperty("login") String login, - @JsonProperty("id") long id, - @JsonProperty("name") String name, - @JsonProperty("company") String company, - @JsonProperty("html_url") String url) { - this.login = login; - this.id = id; - this.name = name; - this.company = company; - this.url = url; - } - - public String getLogin() { - return login; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getCompany() { - return company; - } - - public String getUrl() { - return url; - } - } - - public static class Repository extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("full_name") - private String name; - @JsonProperty("description") - private String description; - @JsonProperty("html_url") - private String url; - - @JsonCreator - public Repository(@JsonProperty("id") long id, - @JsonProperty("full_name") String name, - @JsonProperty("description") String description, - @JsonProperty("html_url") String url) { - this.id = id; - this.name = name; - this.description = description; - this.url = url; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public String getUrl() { - return url; - } - - @Override - public String toString() { - try { - return objectMapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - } - - public static class Issue extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("number") - private long number; - @JsonProperty("title") - private String title; - @JsonProperty("state") - private String state; - @JsonProperty("html_url") - private String url; - @JsonProperty("labels") - private Label[] labels; - @JsonProperty("created_at") - private String createdAt; - @JsonProperty("closed_at") - private String closedAt; - - @JsonCreator - public Issue(@JsonProperty("id") long id, - @JsonProperty("number") long number, - @JsonProperty("title") String title, - @JsonProperty("state") String state, - @JsonProperty("html_url") String url, - @JsonProperty("labels") Label[] labels, - @JsonProperty("created_at") String createdAt, - @JsonProperty("closed_at") String closedAt) { - this.id = id; - this.number = number; - this.title = title; - this.state = state; - this.url = url; - this.labels = labels; - this.createdAt = createdAt; - this.closedAt = closedAt; - } - - public long getId() { - return id; - } - - public long getNumber() { - return number; - } - - public String getTitle() { - return title; - } - - public String getState() { - return state; - } - - public String getUrl() { - return url; - } - - public Label[] getLabels() { - return labels; - } - - public String getCreatedAt() { - return createdAt; - } - - public String getClosedAt() { - return closedAt; - } - } - - public static class IssueDetail extends Issue { - @JsonProperty("body") - private String body; - - @JsonCreator - public IssueDetail(@JsonProperty("id") long id, - @JsonProperty("number") long number, - @JsonProperty("title") String title, - @JsonProperty("state") String state, - @JsonProperty("html_url") String url, - @JsonProperty("labels") Label[] labels, - @JsonProperty("created_at") String createdAt, - @JsonProperty("closed_at") String closedAt, - @JsonProperty("body") String body) { - super(id, number, title, state, url, labels, createdAt, closedAt); - this.body = body; - } - - public String getBody() { - return body; - } - } - - public static class Label extends GitHubModel { - @JsonProperty("id") - private long id; - @JsonProperty("name") - private String name; - @JsonProperty("description") - private String description; - - @JsonCreator - public Label(@JsonProperty("id") long id, - @JsonProperty("name") String name, - @JsonProperty("description") String description) { - this.id = id; - this.name = name; - this.description = description; - } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - } -} diff --git a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java b/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java deleted file mode 100644 index f0bddee10..000000000 --- a/samples/semantickernel-learn-resources/src/main/java/com/microsoft/semantickernel/samples/plugins/github/GitHubPlugin.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.plugins.github; - -import reactor.core.publisher.Mono; -import reactor.netty.http.client.HttpClient; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; - -import java.io.IOException; -import java.util.List; - -public class GitHubPlugin { - public static final String baseUrl = "https://api.github.com"; - private final String token; - - public GitHubPlugin(String token) { - this.token = token; - } - - @DefineKernelFunction(name = "get_user_info", description = "Get user information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$User") - public Mono getUserProfileAsync() { - HttpClient client = createClient(); - - return makeRequestAsync(client, "/user") - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.User.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubUser", e); - } - }); - } - - @DefineKernelFunction(name = "get_repo_info", description = "Get repository information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$Repository") - public Mono getRepositoryAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName) { - HttpClient client = createClient(); - - return makeRequestAsync(client, String.format("/repos/%s/%s", organization, repoName)) - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.Repository.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubRepository", e); - } - }); - } - - @DefineKernelFunction(name = "get_issues", description = "Get issues from GitHub", returnType = "java.util.List") - public Mono> getIssuesAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the organization to retrieve issues for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve issues for") String repoName, - @KernelFunctionParameter(name = "max_results", description = "The maximum number of issues to retrieve", required = false, defaultValue = "10", type = int.class) int maxResults, - @KernelFunctionParameter(name = "state", description = "The state of the issues to retrieve", required = false, defaultValue = "open") String state, - @KernelFunctionParameter(name = "assignee", description = "The assignee of the issues to retrieve", required = false) String assignee) { - HttpClient client = createClient(); - - String query = String.format("/repos/%s/%s/issues", organization, repoName); - query = buildQueryString(query, "state", state); - query = buildQueryString(query, "assignee", assignee); - query = buildQueryString(query, "per_page", String.valueOf(maxResults)); - - return makeRequestAsync(client, query) - .flatMap(json -> { - try { - GitHubModel.Issue[] issues = GitHubModel.objectMapper.readValue(json, - GitHubModel.Issue[].class); - return Mono.just(List.of(issues)); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubIssues", e); - } - }); - } - - @DefineKernelFunction(name = "get_issue_detail_info", description = "Get detail information of a single issue from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$IssueDetail") - public GitHubModel.IssueDetail getIssueDetailAsync( - @KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization, - @KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName, - @KernelFunctionParameter(name = "issue_number", description = "The issue number to retrieve information for", type = int.class) int issueNumber) { - HttpClient client = createClient(); - - return makeRequestAsync(client, - String.format("/repos/%s/%s/issues/%d", organization, repoName, issueNumber)) - .map(json -> { - try { - return GitHubModel.objectMapper.readValue(json, GitHubModel.IssueDetail.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to deserialize GitHubIssue", e); - } - }).block(); - } - - private HttpClient createClient() { - return HttpClient.create() - .baseUrl(baseUrl) - .headers(headers -> { - headers.add("User-Agent", "request"); - headers.add("Accept", "application/vnd.github+json"); - headers.add("Authorization", "Bearer " + token); - headers.add("X-GitHub-Api-Version", "2022-11-28"); - }); - } - - private static String buildQueryString(String path, String param, String value) { - if (value == null || value.isEmpty() - || value.equals(KernelFunctionParameter.NO_DEFAULT_VALUE)) { - return path; - } - - return path + (path.contains("?") ? "&" : "?") + param + "=" + value; - } - - private Mono makeRequestAsync(HttpClient client, String path) { - return client - .get() - .uri(path) - .responseSingle((res, content) -> { - if (res.status().code() != 200) { - return Mono.error(new IllegalStateException("Request failed: " + res.status())); - } - return content.asString(); - }); - } -} diff --git a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/config.json b/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/config.json deleted file mode 100644 index 93e812d18..000000000 --- a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "schema": 1, - "type": "completion", - "description": "Creates a chat response to the user", - "execution_settings": { - "default": { - "max_tokens": 1000, - "temperature": 0 - }, - "gpt-3.5-turbo": { - "model_id": "gpt-3.5-turbo-0613", - "max_tokens": 4000, - "temperature": 0.1 - }, - "gpt-4": { - "model_id": "gpt-4-1106-preview", - "max_tokens": 8000, - "temperature": 0.3 - } - }, - "input_variables": [ - { - "name": "request", - "description": "The user's request.", - "required": true - }, - { - "name": "history", - "description": "The history of the conversation.", - "required": true - } - ] -} \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/skprompt.txt b/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/skprompt.txt deleted file mode 100644 index 82ae0242c..000000000 --- a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/Chat/skprompt.txt +++ /dev/null @@ -1,3 +0,0 @@ -{{ConversationSummaryPlugin.SummarizeConversation $history}} -User: {{$request}} -Assistant: \ No newline at end of file diff --git a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml b/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml deleted file mode 100644 index 3fa1dfbc5..000000000 --- a/samples/semantickernel-learn-resources/src/main/resources/Plugins/Prompts/getIntent.prompt.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: getIntent -description: Gets the intent of the user. -template: | - Instructions: What is the intent of this request? - Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}. - Choices: {{choices}}. - - {{#each fewShotExamples}} - {{#each this}} - {{content}} - {{/each}} - {{/each}} - - Summary of conversation so far: - {{ConversationSummaryPlugin-SummarizeConversation history}} - - - {{request}} - Intent: -template_format: handlebars -input_variables: - - name: choices - description: The choices for the AI to choose from - default: ContinueConversation, EndConversation - - name: fewShotExamples - description: Few shot examples for the AI to learn from - is_required: true - - name: request - description: The user's request - is_required: true -execution_settings: - default: - max_tokens: 10 - temperature: 0 - gpt-3.5-turbo: - model_id: gpt-35-turbo-2 - max_tokens: 10 - temperature: 0.2 - gpt-4: - model_id: gpt-4-1106-preview - max_tokens: 10 - temperature: 0.2 diff --git a/samples/semantickernel-sample-plugins/pom.xml b/samples/semantickernel-sample-plugins/pom.xml deleted file mode 100644 index 0abacea7f..000000000 --- a/samples/semantickernel-sample-plugins/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-sample-plugins - pom - semantickernel-sample-plugins - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - - semantickernel-openapi-plugin - semantickernel-presidio-plugin - semantickernel-text-splitter-plugin - - diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml deleted file mode 100644 index f0b576424..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-openapi-plugin - semantickernel-openapi-plugin - jar - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - - org.apache.logging.log4j - log4j-api - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.azure - azure-identity - - - io.swagger.parser.v3 - swagger-parser - 2.1.22 - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - bug-check - - - false - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - true - - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - - org.codehaus.mojo - exec-maven-plugin - - - run-sample - - java - - - - - com.microsoft.semantickernel.samples.syntaxexamples.${sample} - - - - - diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/OpenAPIHttpRequestPlugin.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/OpenAPIHttpRequestPlugin.java deleted file mode 100644 index ebdc84495..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/OpenAPIHttpRequestPlugin.java +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.openapi; - -import com.azure.core.http.ContentType; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.HttpHeaders; -import com.azure.core.http.HttpMethod; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.HttpResponse; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.parameters.PathParameter; -import io.swagger.v3.oas.models.parameters.QueryParameter; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -/** - * Plugin for making HTTP requests specifically to endpoints discovered via OpenAPI. - */ -public class OpenAPIHttpRequestPlugin { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIHttpRequestPlugin.class); - - private final String serverUrl; - private final String path; - private final PathItem pathItem; - private final HttpClient client; - private final HttpMethod method; - private final Operation operation; - private final HttpHeaders httpHeaders; - - public OpenAPIHttpRequestPlugin( - HttpMethod method, - String serverUrl, - String path, - PathItem pathItem, - HttpClient client, - HttpHeaders httpHeaders, - Operation operation) { - this.method = method; - this.serverUrl = serverUrl; - this.path = path; - this.pathItem = pathItem; - this.client = client; - this.httpHeaders = httpHeaders; - this.operation = operation; - } - - /** - * Executes the HTTP request and return the body of the response. - * - * @param arguments The arguments to the http request. - * @return The body of the response. - */ - public Mono execute(KernelArguments arguments) { - String body = getBody(arguments); - String query = buildQueryString(arguments); - String path = buildQueryPath(arguments); - - String url; - if (!query.isEmpty()) { - url = serverUrl + path + "?" + query; - } else { - url = serverUrl + path; - } - - HttpRequest request = new HttpRequest(method, url); - - HttpHeaders headers = new HttpHeaders(); - if (httpHeaders != null) { - headers = headers.setAllHttpHeaders(httpHeaders); - } - - if (body != null) { - headers = headers.add(HttpHeaderName.CONTENT_TYPE, ContentType.APPLICATION_JSON); - request = request.setBody(body); - } - - if (headers.getSize() > 0) { - request.setHeaders(headers); - } - - LOGGER.debug("Executing {} {}", method.name(), url); - if (body != null) { - LOGGER.debug("Body: {}", body); - } - - return client - .send(request) - .flatMap(response -> { - if (response.getStatusCode() >= 400) { - return Mono.error(new RuntimeException( - "Request failed with status code: " + response.getStatusCode())); - } else { - return Mono.just(response); - } - }) - .flatMap(HttpResponse::getBodyAsString) - .doOnNext(response -> LOGGER.debug("Request response: {}", response)); - } - - private static @Nullable String getBody(KernelArguments arguments) { - String body = null; - if (arguments.containsKey("requestbody")) { - ContextVariable requestBody = arguments.get("requestbody"); - if (requestBody != null) { - try { - JsonNode tree = new ObjectMapper().readTree(requestBody.getValue(String.class)); - body = tree.toPrettyString(); - } catch (JsonProcessingException e) { - body = requestBody.getValue(String.class); - } - } - arguments.remove("requestbody"); - } - return body; - } - - private String buildQueryPath(KernelArguments arguments) { - return getParameterStreamOfArguments(arguments) - .filter(p -> p instanceof PathParameter) - .reduce(path, (path, parameter) -> { - String name = parameter.getName(); - String rendered = getRenderedParameter(arguments, name); - - return path.replaceAll("\\{" + name + "}", rendered); - }, (a, b) -> a + b); - } - - private static String getRenderedParameter( - KernelArguments arguments, String name) { - ContextVariable value = arguments.get(name); - - if (value == null) { - throw new IllegalArgumentException("Missing value for path parameter: " + name); - } - String rendered = value.getValue(String.class); - - if (rendered == null) { - throw new IllegalArgumentException("Path parameter value is null: " + name); - } - return URLEncoder.encode(rendered, StandardCharsets.US_ASCII); - } - - private String buildQueryString(KernelArguments arguments) { - return getParameterStreamOfArguments(arguments) - .filter(p -> p instanceof QueryParameter) - .map(parameter -> { - String name = parameter.getName(); - String rendered = getRenderedParameter(arguments, name); - return name + "=" + rendered; - }) - .collect(Collectors.joining("&")); - } - - private Stream getParameterStreamOfArguments( - KernelArguments arguments) { - if (operation.getParameters() == null) { - return Stream.empty(); - } - return arguments - .keySet() - .stream() - .map(contextVariable -> pathItem - .getGet() - .getParameters() - .stream() - .filter(param -> param.getName().equalsIgnoreCase(contextVariable)).findFirst()) - .filter(Optional::isPresent) - .map(Optional::get); - } -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/SemanticKernelOpenAPIImporter.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/SemanticKernelOpenAPIImporter.java deleted file mode 100644 index 2c01f0767..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/main/java/com/microsoft/semantickernel/samples/openapi/SemanticKernelOpenAPIImporter.java +++ /dev/null @@ -1,618 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.samples.openapi; - -import com.azure.core.http.ContentType; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaders; -import com.azure.core.http.HttpMethod; -import com.azure.core.util.Header; -import com.azure.core.util.HttpClientOptions; -import com.fasterxml.jackson.core.JsonParser.Feature; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.OutputVariable; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.Paths; -import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.BooleanSchema; -import io.swagger.v3.oas.models.media.IntegerSchema; -import io.swagger.v3.oas.models.media.MapSchema; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.NumberSchema; -import io.swagger.v3.oas.models.media.ObjectSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.media.StringSchema; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.parameters.RequestBody; -import io.swagger.v3.oas.models.servers.Server; -import io.swagger.v3.parser.OpenAPIV3Parser; -import io.swagger.v3.parser.core.models.ParseOptions; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SemanticKernelOpenAPIImporter { - - private static final Logger LOGGER = LoggerFactory.getLogger( - SemanticKernelOpenAPIImporter.class); - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private String pluginName; - private String schema; - private HttpHeaders httpHeaders; - private HttpClient client; - private Function, String> serverSelector; - - public Builder withPluginName(String pluginName) { - this.pluginName = pluginName; - return this; - } - - public Builder withSchema(String schema) { - this.schema = schema; - return this; - } - - public Builder withHttpHeaders(HttpHeaders httpHeaders) { - this.httpHeaders = httpHeaders; - return this; - } - - public Builder withClient(HttpClient client) { - this.client = client; - return this; - } - - public Builder withServerSelector(Function, String> serverSelector) { - this.serverSelector = serverSelector; - return this; - } - - public Builder withServer(String serverUrl) { - this.serverSelector = (ignore) -> serverUrl; - return this; - } - - public KernelPlugin build() { - return SemanticKernelOpenAPIImporter.fromSchema(pluginName, schema, httpHeaders, client, - serverSelector); - } - } - - public static KernelPlugin fromSchema( - String pluginName, - String schema, - @Nullable HttpHeaders httpHeaders, - @Nullable HttpClient client, - @Nullable Function, String> serverSelector) { - ParseOptions parseOptions = new ParseOptions(); - parseOptions.setResolve(true); - parseOptions.setResolveFully(true); - - OpenAPI openAPI = new OpenAPIV3Parser().readContents(schema, null, parseOptions) - .getOpenAPI(); - - client = getHttpClient(httpHeaders, client); - - Paths paths = openAPI.getPaths(); - - String serverUrl; - - if (serverSelector != null) { - serverUrl = serverSelector.apply(openAPI.getServers()); - } else { - serverUrl = openAPI.getServers().get(0).getUrl(); - if (openAPI.getServers().size() > 1) { - LOGGER.warn("Multiple servers found, using the first one: {}", serverUrl); - } - } - - Map> functions = getFunctions( - client, - pluginName, - paths, - serverUrl, - httpHeaders); - - return new KernelPlugin( - pluginName, - openAPI.getInfo().getDescription(), - functions); - } - - private static HttpClient getHttpClient( - @Nullable HttpHeaders httpHeaders, - @Nullable HttpClient client) { - - // Currently this does not apply as the Netty client does not obey the headers provided in the - // HttpClientOptions, however they may do one day - if (httpHeaders != null && client != null) { - throw new IllegalArgumentException( - "Both httpHeaders and client cannot be provided at the same time"); - } - - HttpClientOptions options = new HttpClientOptions(); - if (httpHeaders != null) { - options.setHeaders(httpHeaders.stream() - .map(header -> new Header(header.getName(), header.getValuesList())) - .toList()); - } - - if (client == null) { - client = HttpClient.createDefault(options); - } - return client; - } - - private static Map> getFunctions( - HttpClient client, - String pluginName, - Paths paths, - String serverUrl, - HttpHeaders headers) { - return paths - .entrySet() - .stream() - .flatMap((entry) -> { - return formOperation( - client, - pluginName, - serverUrl, - entry.getKey(), - entry.getValue(), - headers) - .stream(); - }) - .collect(Collectors.toMap(KernelFunction::getName, (func) -> func)); - } - - private static List> formOperation( - HttpClient client, - String pluginName, - String serverUrl, - String path, - PathItem pathItem, - HttpHeaders headers) { - - List> plugins = new ArrayList<>(); - - if (pathItem.getGet() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getGet(), - headers, - HttpMethod.GET); - - plugins.add(function); - } - if (pathItem.getDelete() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getDelete(), - headers, - HttpMethod.DELETE); - - plugins.add(function); - } - if (pathItem.getPost() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getPost(), - headers, - HttpMethod.POST); - - plugins.add(function); - } - if (pathItem.getPut() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getPut(), - headers, - HttpMethod.PUT); - - plugins.add(function); - } - if (pathItem.getPatch() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getPatch(), - headers, - HttpMethod.PATCH); - - plugins.add(function); - } - if (pathItem.getOptions() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getOptions(), - headers, - HttpMethod.OPTIONS); - - plugins.add(function); - } - if (pathItem.getHead() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getHead(), - headers, - HttpMethod.HEAD); - - plugins.add(function); - } - if (pathItem.getTrace() != null) { - var function = getKernelFunctionFromRequest( - client, - pluginName, - serverUrl, - path, - pathItem, - pathItem.getTrace(), - headers, - HttpMethod.TRACE); - - plugins.add(function); - } - - return plugins; - } - - private static @Nullable KernelFunction getKernelFunctionFromRequest( - HttpClient client, - String pluginName, - String serverUrl, - String path, - PathItem pathItem, - Operation operation, - HttpHeaders headers, - HttpMethod method) { - - List variableList = getInputVariables(operation); - OutputVariable ov = getOutputVariable(operation); - String description = getDescription(operation.getDescription()); - - OpenAPIHttpRequestPlugin plugin = new OpenAPIHttpRequestPlugin( - method, - serverUrl, - path, - pathItem, - client, - headers, - operation); - - RequestBody requestBody = operation.getRequestBody(); - - if (requestBody != null) { - if (requestBody.getContent().get(ContentType.APPLICATION_JSON) != null) { - MediaType mediaType = requestBody.getContent().get(ContentType.APPLICATION_JSON); - Schema schema = mediaType.getSchema(); - - String example = renderJsonExample(schema); - - try { - JsonNode parsed = new ObjectMapper() - .enable(Feature.ALLOW_TRAILING_COMMA) - .readTree(example); - example = parsed.get("root").toPrettyString(); - } catch (JsonProcessingException e) { - throw new RuntimeException("Failed to parse example JSON", e); - } - - List enums = getEnumValues(schema); - - variableList = new ArrayList<>(variableList); - variableList.add(InputVariable.build( - "requestBody", - String.class, - "Example request body:\n" + example, - example, - enums, - true)); - - } else { - LOGGER.warn("No content type found for operation {}", operation.getOperationId()); - } - } - - return buildKernelFunction(pluginName, plugin, operation, description, variableList, ov); - } - - private static String renderJsonExample(Schema schema) { - StringBuilder stringBuilder = new StringBuilder(); - renderJsonExample(stringBuilder, "root", schema); - return "{" + stringBuilder + "}"; - } - - private static void renderJsonExample( - StringBuilder stringBuilder, - String valueKey, - Schema schema) { - - if (schema.getExample() != null) { - if (valueKey != null) { - stringBuilder.append("\"").append(valueKey).append("\": "); - } - - if (schema instanceof StringSchema) { - stringBuilder.append("\"").append(schema.getExample().toString()).append("\","); - } else { - stringBuilder.append(schema.getExample().toString()).append(","); - } - return; - } - - if (schema instanceof IntegerSchema || - schema instanceof StringSchema || - schema instanceof NumberSchema || - schema instanceof BooleanSchema) { - - String value; - - if (schema instanceof IntegerSchema) { - value = "1"; - } else if (schema instanceof StringSchema) { - if (schema.getEnum() != null && !schema.getEnum().isEmpty()) { - value = "\"" + schema.getEnum().get(0).toString() + "\""; - } else { - value = "\"string\""; - } - } else if (schema instanceof NumberSchema) { - value = "1.0"; - } else { - value = "true"; - } - - if (valueKey != null) { - stringBuilder.append("\"").append(valueKey).append("\": "); - } - stringBuilder.append(value).append(","); - - } else if (schema instanceof ObjectSchema objectSchema) { - - if (valueKey != null) { - stringBuilder.append("\"").append(valueKey).append("\": "); - } - - stringBuilder.append("{"); - - objectSchema.getProperties().forEach((key, value) -> { - renderJsonExample(stringBuilder, key, value); - }); - stringBuilder.append("},"); - } else if (schema instanceof ArraySchema arraySchema) { - - if (valueKey != null) { - stringBuilder.append("\"").append(valueKey).append("\": "); - } - - stringBuilder.append("["); - renderJsonExample(stringBuilder, null, - arraySchema.getItems()); - stringBuilder.append("],"); - - } else if (schema instanceof MapSchema) { - throw new SKException("Not yet supported"); - } else { - LOGGER.warn("Unsupported schema type {}", schema.getClass().getName()); - } - } - - private static String renderXmlExample(Schema schema) { - StringBuilder stringBuilder = new StringBuilder(); - renderXmlExample(stringBuilder, null, schema); - return stringBuilder.toString(); - } - - private static void renderXmlExample(StringBuilder stringBuilder, String valueKey, - Schema schema) { - - if (schema.getExample() != null) { - stringBuilder.append("<").append(valueKey).append(">"); - stringBuilder.append(schema.getExample().toString()); - stringBuilder.append(""); - return; - } - - if (schema instanceof IntegerSchema || - schema instanceof StringSchema || - schema instanceof NumberSchema || - schema instanceof BooleanSchema) { - - String value; - - if (schema instanceof IntegerSchema) { - value = "1"; - } else if (schema instanceof StringSchema) { - if (schema.getEnum() != null && !schema.getEnum().isEmpty()) { - value = schema.getEnum().get(0).toString(); - } else { - value = "string"; - } - } else if (schema instanceof NumberSchema) { - value = "1.0"; - } else { - value = "true"; - } - - stringBuilder.append("<").append(valueKey).append(">"); - stringBuilder.append(value); - stringBuilder.append(""); - } else if (schema instanceof ObjectSchema objectSchema) { - - String nameTag = "<" + schema.getXml().getName() + ">"; - String closingNameTag = ""; - - stringBuilder.append(nameTag); - objectSchema.getProperties().forEach((key, value) -> { - renderXmlExample(stringBuilder, key, value); - }); - stringBuilder.append(closingNameTag); - } else if (schema instanceof ArraySchema arraySchema) { - String nameTag = "<" + valueKey + ">"; - String closingNameTag = ""; - stringBuilder.append(nameTag); - renderXmlExample(stringBuilder, arraySchema.getItems().getXml().getName(), - arraySchema.getItems()); - stringBuilder.append(closingNameTag); - } else if (schema instanceof MapSchema) { - throw new SKException("Not yet supported"); - } else { - LOGGER.warn("Unsupported schema type {}", schema.getClass().getName()); - } - } - - private static KernelFunction buildKernelFunction( - String pluginName, - OpenAPIHttpRequestPlugin plugin, - Operation operation, - String description, - List variableList, - OutputVariable ov) { - - try { - Method method = OpenAPIHttpRequestPlugin.class.getMethod("execute", - KernelArguments.class); - - return KernelFunction - .createFromMethod(method, plugin) - .withFunctionName(operation.getOperationId()) - .withPluginName(pluginName) - .withDescription(description) - .withParameters(variableList) - .withReturnParameter(ov) - .build(); - } catch (NoSuchMethodException e) { - return null; - } - } - - private static OutputVariable getOutputVariable(Operation get) { - return new OutputVariable<>( - get.getDescription(), - String.class); - } - - private static @Nullable String getDescription(String get) { - String description = get; - if (description != null) { - description = StringEscapeUtils.escapeXml11(description); - description = description.replaceAll("\\n", ""); - } - return description; - } - - private static List getInputVariables(Operation get) { - List variableList = List.of(); - if (get.getParameters() != null) { - variableList = get - .getParameters() - .stream() - .map(parameter -> { - Class type = getType(parameter); - - Object def = parameter.getSchema().getDefault(); - - String description = getDescription(parameter.getDescription()); - - List enums = getEnumValues(parameter.getSchema()); - - return InputVariable.build( - parameter.getName(), - type, - description, - def != null ? def.toString() : null, - enums, - parameter.getRequired()); - }) - .collect(Collectors.toList()); - } - return variableList; - } - - private static List getEnumValues(Schema parameter) { - if (parameter.getEnum() == null) { - return null; - } - return parameter.getEnum() - .stream() - .map(Object::toString) - .toList(); - } - - private static Class getType(Parameter parameter) { - Class type = String.class; - String t = parameter.getSchema().getType(); - if (t != null) { - switch (t) { - case "integer": - type = Integer.class; - break; - case "number": - type = Double.class; - break; - case "boolean": - type = Boolean.class; - break; - case "array": - type = List.class; - break; - - // Not sure if we can support this - case "null": - break; - case "object": - break; - default: - break; - } - } - return type; - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAdoptiumImporter.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAdoptiumImporter.java deleted file mode 100644 index b1c77c337..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAdoptiumImporter.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.samples.openapi.SemanticKernelOpenAPIImporter; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import java.io.FileNotFoundException; - -public class ExampleAdoptiumImporter { - - public static void main(String[] args) throws FileNotFoundException { - runJson(); - runYaml(); - } - - private static void runJson() throws FileNotFoundException { - String json = EmbeddedResourceLoader.readFile("adoptium.json", - ExampleAdoptiumImporter.class); - makeRequests(json); - } - - private static void runYaml() throws FileNotFoundException { - String yaml = EmbeddedResourceLoader.readFile("adoptium.yaml", - ExampleAdoptiumImporter.class); - makeRequests(yaml); - } - - private static void makeRequests(String schema) { - KernelPlugin plugin = SemanticKernelOpenAPIImporter - .builder() - .withPluginName("adoptium") - .withSchema(schema) - .build(); - - Kernel kernel = ExampleOpenAPIParent.kernelBuilder() - .withPlugin(plugin) - .build(); - - performRequest(kernel, - """ - Parse the java version 11.0.22+9? - """); - - performRequest(kernel, - """ - What are the names of the GA versions of Java available between 8 and 9 inclusive? - """); - - performRequest(kernel, - """ - What is the version of the latest GA release of Java between 11 and 12? - """); - } - - private static void performRequest(Kernel kernel, String request) { - KernelFunction function = KernelFunction.createFromPrompt(request) - .build(); - - FunctionResult result = kernel.invokeAsync(function) - .withResultType(String.class) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .block(); - - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAuthenticatedRequestImporter.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAuthenticatedRequestImporter.java deleted file mode 100644 index 3be277c82..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleAuthenticatedRequestImporter.java +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -import com.azure.core.http.HttpHeader; -import com.azure.core.http.HttpHeaders; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.samples.openapi.SemanticKernelOpenAPIImporter; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.sun.net.httpserver.HttpServer; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.List; -import org.junit.jupiter.api.Assertions; - -public class ExampleAuthenticatedRequestImporter { - - public static void main(String[] args) throws IOException { - - String yaml = EmbeddedResourceLoader.readFile("authenticatedRequest.yaml", - ExampleAuthenticatedRequestImporter.class); - - KernelPlugin plugin = SemanticKernelOpenAPIImporter - .builder() - .withPluginName("authenticatedRequest") - .withSchema(yaml) - .withServer("http://127.0.0.1:8890") - .withHttpHeaders(new HttpHeaders(List.of( - new HttpHeader("Authorization", "Bearer 1234")))) - .build(); - - Kernel kernel = ExampleOpenAPIParent.kernelBuilder() - .withPlugin(plugin) - .build(); - HttpServer httpServer = null; - try { - httpServer = HttpServer.create(new InetSocketAddress("127.0.0.1", 8890), 0); - httpServer.createContext("/state", exchange -> { - - Assertions.assertTrue( - exchange.getRequestHeaders().containsKey("Authorization"), - "Authorization header not found"); - - exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); - exchange.getResponseBody().write( - """ - { - "state": "running" - } - """ - .stripIndent() - .getBytes(StandardCharsets.UTF_8)); - exchange.close(); - }); - httpServer.start(); - - performRequest(kernel, - """ - What is the current state of the system? - """.stripIndent()); - - } finally { - httpServer.stop(0); - } - - } - - private static void performRequest(Kernel kernel, String request) { - KernelFunction function = KernelFunction.createFromPrompt(request) - .build(); - - FunctionResult result = kernel.invokeAsync(function) - .withResultType(String.class) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .block(); - - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleOpenAPIParent.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleOpenAPIParent.java deleted file mode 100644 index 5132af8f0..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExampleOpenAPIParent.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -import com.azure.ai.openai.OpenAIAsyncClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.core.credential.AzureKeyCredential; -import com.azure.core.credential.KeyCredential; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.Kernel.Builder; -import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; - -public class ExampleOpenAPIParent { - - private static final String PLUGIN_DIR = System.getenv("PLUGIN_DIR") == null ? "." - : System.getenv("PLUGIN_DIR"); - private static final String CLIENT_KEY = System.getenv("CLIENT_KEY"); - private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); - - // Only required if AZURE_CLIENT_KEY is set - private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); - private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-35-turbo-2"); - - public static Builder kernelBuilder() { - - OpenAIAsyncClient client; - - if (AZURE_CLIENT_KEY != null) { - client = new OpenAIClientBuilder() - .credential(new AzureKeyCredential(AZURE_CLIENT_KEY)) - .endpoint(CLIENT_ENDPOINT) - .buildAsyncClient(); - - } else { - client = new OpenAIClientBuilder() - .credential(new KeyCredential(CLIENT_KEY)) - .buildAsyncClient(); - } - - ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder() - .withOpenAIAsyncClient(client) - .withModelId(MODEL_ID) - .build(); - - return Kernel.builder() - .withAIService(ChatCompletionService.class, openAIChatCompletion); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExamplePetstoreImporter.java b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExamplePetstoreImporter.java deleted file mode 100644 index 499670753..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/java/ExamplePetstoreImporter.java +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.samples.openapi.SemanticKernelOpenAPIImporter; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import java.io.FileNotFoundException; - -public class ExamplePetstoreImporter { - - public static void main(String[] args) throws FileNotFoundException { - - String yaml = EmbeddedResourceLoader.readFile("petstore.yaml", - ExamplePetstoreImporter.class); - - KernelPlugin plugin = SemanticKernelOpenAPIImporter - .builder() - .withPluginName("petstore") - .withSchema(yaml) - .withServer("http://localhost:8090/api/v3") - .build(); - - Kernel kernel = ExampleOpenAPIParent.kernelBuilder() - .withPlugin(plugin) - .build(); - - performRequest(kernel, - """ - Create a user with the following details: - username: john_doe - first name: John - last name: Doe - email: john_doe@example.com - password: password123 - phone: 1234567890 - user status: 1"""); - performRequest(kernel, "Add a new cat called Sandy to the store."); - performRequest(kernel, "List all available pets."); - - } - - private static void performRequest(Kernel kernel, String request) { - KernelFunction function = KernelFunction.createFromPrompt(request) - .build(); - - FunctionResult result = kernel.invokeAsync(function) - .withResultType(String.class) - .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)) - .block(); - - System.out.println(result.getResult()); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.json b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.json deleted file mode 100644 index 9b439f427..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.json +++ /dev/null @@ -1,1857 +0,0 @@ -{ - "openapi" : "3.0.3", - "info" : { - "title" : "v3", - "description" : "", - "version" : "3.0.0" - }, - "servers" : [ { - "url" : "https://api.adoptium.net" - }, { - "url" : "https://staging-api.adoptium.net" - } ], - "tags" : [ { - "name" : "Assets" - }, { - "name" : "Binary" - }, { - "name" : "Checksum" - }, { - "name" : "Installer" - }, { - "name" : "Release Info" - }, { - "name" : "Signature" - }, { - "name" : "Version" - } ], - "paths" : { - "/v3/assets/feature_releases/{feature_version}/{release_type}" : { - "get" : { - "tags" : [ "Assets" ], - "summary" : "Returns release information", - "description" : "List of information about builds that match the current query", - "operationId" : "searchReleases", - "parameters" : [ { - "name" : "feature_version", - "in" : "path", - "description" : "\n

\n Feature release version you wish to download. Feature versions are whole numbers e.g. 8,11,16,17,18.\n

\n

\n Available Feature versions can be obtained from \n https://api.adoptium.net/v3/info/available_releases\n

\n", - "required" : true, - "schema" : { - "default" : 8, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "release_type", - "in" : "path", - "description" : "\n

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

\n", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "before", - "in" : "query", - "description" : "

Return binaries whose updated_at is before the given date/time. When a date is given the match is inclusive of the given day.

  • 2020-01-21
  • 2020-01-21T10:15:30
  • 20200121
  • 2020-12-21T10:15:30Z
  • 2020-12-21+01:00

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/DateTime" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "query", - "description" : "Heap Size", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "query", - "description" : "JVM Implementation", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "page", - "in" : "query", - "description" : "Pagination page number", - "required" : false, - "schema" : { - "default" : 0, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "page_size", - "in" : "query", - "description" : "Pagination page size", - "required" : false, - "schema" : { - "default" : 10, - "maximum" : 20, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - }, { - "name" : "sort_method", - "in" : "query", - "description" : "Result sort method", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortMethod" - }, { - "nullable" : true - } ] - } - }, { - "name" : "sort_order", - "in" : "query", - "description" : "Result sort order", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortOrder" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "query", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "200" : { - "description" : "search results matching criteria", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Release" - } - } - } - } - }, - "400" : { - "description" : "bad input parameter" - } - } - } - }, - "/v3/assets/latest/{feature_version}/{jvm_impl}" : { - "get" : { - "tags" : [ "Assets" ], - "summary" : "Returns list of latest assets for the given feature version and jvm impl", - "operationId" : "getLatestAssets", - "parameters" : [ { - "name" : "feature_version", - "in" : "path", - "description" : "\n

\n Feature release version you wish to download. Feature versions are whole numbers e.g. 8,11,16,17,18.\n

\n

\n Available Feature versions can be obtained from \n https://api.adoptium.net/v3/info/available_releases\n

\n", - "required" : true, - "schema" : { - "default" : 8, - "type" : "integer" - } - }, { - "name" : "jvm_impl", - "in" : "path", - "description" : "JVM Implementation", - "required" : true, - "schema" : { - "$ref" : "#/components/schemas/JvmImpl" - } - }, { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "query", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/BinaryAssetView" - } - } - } - } - } - } - } - }, - "/v3/assets/release_name/{vendor}/{release_name}" : { - "get" : { - "tags" : [ "Assets" ], - "summary" : "Returns release information", - "description" : "List of releases with the given release name", - "operationId" : "getReleaseInfo", - "parameters" : [ { - "name" : "release_name", - "in" : "path", - "description" : "Name of the release i.e ", - "required" : true, - "schema" : { - "type" : "string", - "nullable" : true - } - }, { - "name" : "vendor", - "in" : "path", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - }, { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "query", - "description" : "Heap Size", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "query", - "description" : "JVM Implementation", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "200" : { - "description" : "Release with the given vendor and name", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/Release" - } - } - } - }, - "400" : { - "description" : "bad input parameter" - }, - "404" : { - "description" : "no releases match the request" - }, - "500" : { - "description" : "multiple releases match the request" - } - } - } - }, - "/v3/assets/version/{version}" : { - "get" : { - "tags" : [ "Assets" ], - "summary" : "Returns release information about the specified version.", - "description" : "List of information about builds that match the current query ", - "operationId" : "searchReleasesByVersion", - "parameters" : [ { - "name" : "version", - "in" : "path", - "description" : "\nJava version range (maven style) of versions to include.\n\ne.g:\n* `11.0.4.1+11.1`\n* `[1.0,2.0)`\n* `(,1.0]`\n\nDetails of maven version ranges can be found at\n \n", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "query", - "description" : "Heap Size", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "query", - "description" : "JVM Implementation", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "lts", - "in" : "query", - "description" : "Include only LTS releases", - "required" : false, - "schema" : { - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "page", - "in" : "query", - "description" : "Pagination page number", - "required" : false, - "schema" : { - "default" : 0, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "page_size", - "in" : "query", - "description" : "Pagination page size", - "required" : false, - "schema" : { - "default" : 10, - "maximum" : 20, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - }, { - "name" : "release_type", - "in" : "query", - "description" : "\n

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

\n", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "semver", - "in" : "query", - "description" : "Indicates that any version arguments provided in this request were Adoptium semantic versions", - "required" : false, - "schema" : { - "default" : false, - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "sort_method", - "in" : "query", - "description" : "Result sort method", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortMethod" - }, { - "nullable" : true - } ] - } - }, { - "name" : "sort_order", - "in" : "query", - "description" : "Result sort order", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortOrder" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "query", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "200" : { - "description" : "search results matching criteria", - "content" : { - "application/json" : { - "schema" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Release" - } - } - } - } - }, - "400" : { - "description" : "bad input parameter" - } - } - } - }, - "/v3/binary/latest/{feature_version}/{release_type}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}" : { - "get" : { - "tags" : [ "Binary" ], - "summary" : "Redirects to the binary that matches your current query", - "description" : "Redirects to the binary that matches your current query", - "operationId" : "getBinary", - "parameters" : [ { - "name" : "arch", - "in" : "path", - "description" : "Architecture", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "feature_version", - "in" : "path", - "description" : "\n

\n Feature release version you wish to download. Feature versions are whole numbers e.g. 8,11,16,17,18.\n

\n

\n Available Feature versions can be obtained from \n https://api.adoptium.net/v3/info/available_releases\n

\n", - "required" : true, - "schema" : { - "default" : 8, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "heap_size", - "in" : "path", - "description" : "Heap Size", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "path", - "description" : "Image Type", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "path", - "description" : "JVM Implementation", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "os", - "in" : "path", - "description" : "Operating System", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "release_type", - "in" : "path", - "description" : "\n

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

\n", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "path", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "307" : { - "description" : "link to binary that matches your current query" - }, - "400" : { - "description" : "bad input parameter" - }, - "404" : { - "description" : "No matching binary found" - } - } - } - }, - "/v3/binary/version/{release_name}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}" : { - "get" : { - "tags" : [ "Binary" ], - "summary" : "Redirects to the binary that matches your current query", - "description" : "Redirects to the binary that matches your current query", - "operationId" : "getBinaryByVersion", - "parameters" : [ { - "name" : "arch", - "in" : "path", - "description" : "Architecture", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "path", - "description" : "Heap Size", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "path", - "description" : "Image Type", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "path", - "description" : "JVM Implementation", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "os", - "in" : "path", - "description" : "Operating System", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "release_name", - "in" : "path", - "description" : "\n

\n Name of the release as displayed in github or https://adoptopenjdk.net/ e.g\n jdk-11.0.4+11, jdk8u172-b00-201807161800.\n

\n

\n A list of release names can be obtained from \n https://api.adoptium.net/v3/info/release_names\n

\n", - "required" : true, - "schema" : { - "default" : "jdk-11.0.6+10", - "type" : "string", - "nullable" : true - } - }, { - "name" : "vendor", - "in" : "path", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : true, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - } ], - "responses" : { - "307" : { - "description" : "link to binary that matches your current query" - }, - "400" : { - "description" : "bad input parameter" - }, - "404" : { - "description" : "No matching binary found" - } - } - } - }, - "/v3/info/available_releases" : { - "get" : { - "tags" : [ "Release Info" ], - "summary" : "Returns information about available releases", - "operationId" : "getAvailableReleases", - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ReleaseInfo" - } - } - } - } - } - } - }, - "/v3/info/release_names" : { - "get" : { - "tags" : [ "Release Info" ], - "summary" : "Returns a list of all release names", - "operationId" : "getReleaseNames", - "parameters" : [ { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "query", - "description" : "Heap Size", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "query", - "description" : "JVM Implementation", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "lts", - "in" : "query", - "description" : "Include only LTS releases", - "required" : false, - "schema" : { - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "page", - "in" : "query", - "description" : "Pagination page number", - "required" : false, - "schema" : { - "default" : 0, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "page_size", - "in" : "query", - "description" : "Pagination page size", - "required" : false, - "schema" : { - "default" : 10, - "maximum" : 20, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - }, { - "name" : "release_type", - "in" : "query", - "description" : "\n

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

\n", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "semver", - "in" : "query", - "description" : "Indicates that any version arguments provided in this request were Adoptium semantic versions", - "required" : false, - "schema" : { - "default" : false, - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "sort_method", - "in" : "query", - "description" : "Result sort method", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortMethod" - }, { - "nullable" : true - } ] - } - }, { - "name" : "sort_order", - "in" : "query", - "description" : "Result sort order", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortOrder" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "query", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - }, { - "name" : "version", - "in" : "query", - "description" : "\nJava version range (maven style) of versions to include.\n\ne.g:\n* `11.0.4.1+11.1`\n* `[1.0,2.0)`\n* `(,1.0]`\n\nDetails of maven version ranges can be found at\n \n", - "required" : false, - "schema" : { - "type" : "string", - "nullable" : true - } - } ], - "responses" : { - "200" : { - "description" : "A list of all release names", - "content" : { - "application/json" : { - "schema" : { - "required" : [ "releases" ], - "type" : "object", - "properties" : { - "releases" : { - "type" : "array", - "items" : { - "type" : "string" - } - } - } - } - } - } - } - } - } - }, - "/v3/info/release_versions" : { - "get" : { - "tags" : [ "Release Info" ], - "summary" : "Returns a list of all release versions", - "operationId" : "getReleaseVersions", - "parameters" : [ { - "name" : "architecture", - "in" : "query", - "description" : "Architecture", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Architecture" - }, { - "nullable" : true - } ] - } - }, { - "name" : "c_lib", - "in" : "query", - "description" : "C Lib type, typically would imply image_type has been set to staticlibs", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - }, { - "nullable" : true - } ] - } - }, { - "name" : "heap_size", - "in" : "query", - "description" : "Heap Size", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/HeapSize" - }, { - "nullable" : true - } ] - } - }, { - "name" : "image_type", - "in" : "query", - "description" : "Image Type", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ImageType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "jvm_impl", - "in" : "query", - "description" : "JVM Implementation", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/JvmImpl" - }, { - "nullable" : true - } ] - } - }, { - "name" : "lts", - "in" : "query", - "description" : "Include only LTS releases", - "required" : false, - "schema" : { - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "os", - "in" : "query", - "description" : "Operating System", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/OperatingSystem" - }, { - "nullable" : true - } ] - } - }, { - "name" : "page", - "in" : "query", - "description" : "Pagination page number", - "required" : false, - "schema" : { - "default" : 0, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "page_size", - "in" : "query", - "description" : "Pagination page size", - "required" : false, - "schema" : { - "default" : 10, - "maximum" : 50, - "type" : "integer", - "nullable" : true - } - }, { - "name" : "project", - "in" : "query", - "description" : "Project", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/project" - }, { - "nullable" : true - } ] - } - }, { - "name" : "release_type", - "in" : "query", - "description" : "\n

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

\n", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseType" - }, { - "nullable" : true - } ] - } - }, { - "name" : "semver", - "in" : "query", - "description" : "Indicates that any version arguments provided in this request were Adoptium semantic versions", - "required" : false, - "schema" : { - "default" : false, - "type" : "boolean", - "nullable" : true - } - }, { - "name" : "sort_method", - "in" : "query", - "description" : "Result sort method", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortMethod" - }, { - "nullable" : true - } ] - } - }, { - "name" : "sort_order", - "in" : "query", - "description" : "Result sort order", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/SortOrder" - }, { - "nullable" : true - } ] - } - }, { - "name" : "vendor", - "in" : "query", - "description" : "

Vendor of the binary. This is the organisation that produced the binary package.

", - "required" : false, - "schema" : { - "allOf" : [ { - "$ref" : "#/components/schemas/Vendor" - }, { - "nullable" : true - } ] - } - }, { - "name" : "version", - "in" : "query", - "description" : "\nJava version range (maven style) of versions to include.\n\ne.g:\n* `11.0.4.1+11.1`\n* `[1.0,2.0)`\n* `(,1.0]`\n\nDetails of maven version ranges can be found at\n \n", - "required" : false, - "schema" : { - "type" : "string", - "nullable" : true - } - } ], - "responses" : { - "200" : { - "description" : "A list of all release versions", - "content" : { - "application/json" : { - "schema" : { - "required" : [ "versions" ], - "type" : "object", - "properties" : { - "versions" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/VersionData" - } - } - } - } - } - } - } - } - } - }, - "/v3/version/{version}" : { - "get" : { - "tags" : [ "Version" ], - "summary" : "Parses a java version string", - "description" : "Parses a java version string and returns that data in a structured format", - "operationId" : "parseVersion", - "parameters" : [ { - "name" : "version", - "in" : "path", - "description" : "Version", - "required" : true, - "schema" : { - "type" : "string", - "nullable" : true - } - } ], - "responses" : { - "400" : { - "description" : "bad input parameter" - } - } - } - } - }, - "components" : { - "schemas" : { - "AdoptiumJvmImpl" : { - "enum" : [ "hotspot" ], - "type" : "string" - }, - "AdoptiumVendor" : { - "default" : "eclipse", - "enum" : [ "eclipse" ], - "type" : "string", - "example" : "eclipse" - }, - "Architecture" : { - "enum" : [ "x64", "x86", "x32", "ppc64", "ppc64le", "s390x", "aarch64", "arm", "sparcv9", "riscv64" ], - "type" : "string" - }, - "Binary" : { - "required" : [ "os", "architecture", "image_type", "jvm_impl", "heap_size", "updated_at", "project" ], - "type" : "object", - "properties" : { - "os" : { - "$ref" : "#/components/schemas/OperatingSystem" - }, - "architecture" : { - "$ref" : "#/components/schemas/Architecture" - }, - "image_type" : { - "$ref" : "#/components/schemas/ImageType" - }, - "c_lib" : { - "type" : "string", - "allOf" : [ { - "$ref" : "#/components/schemas/CLib" - } ], - "nullable" : true - }, - "jvm_impl" : { - "$ref" : "#/components/schemas/JvmImpl" - }, - "package" : { - "$ref" : "#/components/schemas/Package" - }, - "installer" : { - "$ref" : "#/components/schemas/Installer" - }, - "heap_size" : { - "$ref" : "#/components/schemas/HeapSize" - }, - "download_count" : { - "format" : "int64", - "type" : "integer", - "example" : 3899 - }, - "updated_at" : { - "$ref" : "#/components/schemas/DateTime" - }, - "scm_ref" : { - "type" : "string", - "example" : "dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93", - "nullable" : true - }, - "project" : { - "$ref" : "#/components/schemas/project" - } - } - }, - "BinaryAssetView" : { - "required" : [ "release_name", "release_link" ], - "type" : "object", - "properties" : { - "binary" : { - "$ref" : "#/components/schemas/Binary" - }, - "release_name" : { - "type" : "string", - "example" : "jdk8u162-b12_openj9-0.8.0" - }, - "release_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/tag/jdk8u162-b12_openj9-0.8.0" - }, - "vendor" : { - "$ref" : "#/components/schemas/Vendor" - }, - "version" : { - "$ref" : "#/components/schemas/VersionData" - } - } - }, - "CLib" : { - "enum" : [ "musl", "glibc" ], - "type" : "string" - }, - "DateTime" : { - "description" : "

Date/time. When only a date is given the time is set to the end of the given day.

  • 2020-01-21
  • 2020-01-21T10:15:30
  • 20200121
  • 2020-12-21T10:15:30Z
  • 2020-12-21+01:00

", - "type" : "string" - }, - "HeapSize" : { - "enum" : [ "normal", "large" ], - "type" : "string", - "example" : "normal" - }, - "ImageType" : { - "enum" : [ "jdk", "jre", "testimage", "debugimage", "staticlibs", "sources", "sbom" ], - "type" : "string", - "example" : "jdk" - }, - "Installer" : { - "required" : [ "name", "link" ], - "type" : "object", - "properties" : { - "name" : { - "type" : "string", - "example" : "OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi" - }, - "link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-binaries/ga/download/jdk8u212-b04/OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi" - }, - "size" : { - "format" : "int64", - "type" : "integer", - "example" : 82573385 - }, - "checksum" : { - "type" : "string", - "example" : "dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93", - "nullable" : true - }, - "checksum_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.sha256.txt", - "nullable" : true - }, - "signature_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jdk_x64_linux_11.0.5_10.tar.gz.sign", - "nullable" : true - }, - "download_count" : { - "format" : "int64", - "type" : "integer", - "example" : 2 - }, - "metadata_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.json", - "nullable" : true - } - } - }, - "JvmImpl" : { - "$ref" : "#/components/schemas/AdoptiumJvmImpl" - }, - "OperatingSystem" : { - "enum" : [ "linux", "windows", "mac", "solaris", "aix", "alpine-linux" ], - "type" : "string" - }, - "Package" : { - "required" : [ "name", "link" ], - "type" : "object", - "properties" : { - "name" : { - "type" : "string", - "example" : "OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi" - }, - "link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-binaries/ga/download/jdk8u212-b04/OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi" - }, - "size" : { - "format" : "int64", - "type" : "integer", - "example" : 82573385 - }, - "checksum" : { - "type" : "string", - "example" : "dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93", - "nullable" : true - }, - "checksum_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.sha256.txt", - "nullable" : true - }, - "signature_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jdk_x64_linux_11.0.5_10.tar.gz.sign", - "nullable" : true - }, - "download_count" : { - "format" : "int64", - "type" : "integer", - "example" : 2 - }, - "metadata_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.json", - "nullable" : true - } - } - }, - "Release" : { - "required" : [ "id", "release_link", "release_name", "timestamp", "updated_at", "binaries", "release_type", "vendor", "version_data" ], - "type" : "object", - "properties" : { - "id" : { - "type" : "string", - "example" : "VXNlci0xMA==" - }, - "release_link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/tag/jdk8u162-b12_openj9-0.8.0" - }, - "release_name" : { - "type" : "string", - "example" : "jdk8u162-b12_openj9-0.8.0" - }, - "timestamp" : { - "$ref" : "#/components/schemas/DateTime" - }, - "updated_at" : { - "$ref" : "#/components/schemas/DateTime" - }, - "binaries" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Binary" - } - }, - "download_count" : { - "format" : "int64", - "type" : "integer", - "example" : 7128 - }, - "release_type" : { - "$ref" : "#/components/schemas/ReleaseType" - }, - "vendor" : { - "$ref" : "#/components/schemas/Vendor" - }, - "version_data" : { - "$ref" : "#/components/schemas/VersionData" - }, - "source" : { - "type" : "object", - "allOf" : [ { - "$ref" : "#/components/schemas/SourcePackage" - } ], - "nullable" : true - }, - "release_notes" : { - "type" : "object", - "allOf" : [ { - "$ref" : "#/components/schemas/ReleaseNotesPackage" - } ], - "nullable" : true - }, - "aqavit_results_link" : { - "type" : "string", - "example" : "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6%2B10/AQAvitTapFiles.tar.gz", - "nullable" : true - } - } - }, - "ReleaseInfo" : { - "required" : [ "available_releases", "available_lts_releases" ], - "type" : "object", - "properties" : { - "available_releases" : { - "description" : "The versions for which adopt have produced a ga release", - "type" : "array", - "items" : { - "format" : "int32", - "type" : "integer" - }, - "example" : [ 8, 9, 10, 11, 12, 13, 14 ] - }, - "available_lts_releases" : { - "description" : "The LTS versions for which adopt have produced a ga release", - "type" : "array", - "items" : { - "format" : "int32", - "type" : "integer" - }, - "example" : [ 8, 11 ] - }, - "most_recent_lts" : { - "format" : "int32", - "description" : "The highest LTS version for which adopt have produced a ga release", - "type" : "integer", - "example" : 11 - }, - "most_recent_feature_release" : { - "format" : "int32", - "description" : "The highest version (LTS or not) for which adopt have produced a ga release", - "type" : "integer", - "example" : 13 - }, - "most_recent_feature_version" : { - "format" : "int32", - "description" : "The highest version (LTS or not) for which we have produced a build, this may be a version that has not yet produced a ga release", - "type" : "integer", - "example" : 15 - }, - "tip_version" : { - "format" : "int32", - "description" : "The version that is currently in development at openjdk", - "type" : "integer", - "example" : 15 - } - } - }, - "ReleaseNote" : { - "required" : [ "id" ], - "type" : "object", - "properties" : { - "id" : { - "type" : "string" - }, - "title" : { - "type" : "string", - "nullable" : true - }, - "priority" : { - "type" : "string", - "nullable" : true - }, - "component" : { - "type" : "string", - "nullable" : true - }, - "subcomponent" : { - "type" : "string", - "nullable" : true - }, - "link" : { - "type" : "string", - "nullable" : true - }, - "type" : { - "type" : "string", - "nullable" : true - }, - "backportOf" : { - "type" : "string", - "nullable" : true - } - } - }, - "ReleaseNotesPackage" : { - "required" : [ "name", "link" ], - "type" : "object", - "properties" : { - "name" : { - "type" : "string", - "example" : "OpenJDK8U-sources_8u232b09.tar.gz" - }, - "link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u232-b09/OpenJDK8U-sources_8u232b09.tar.gz" - }, - "size" : { - "format" : "int64", - "type" : "integer", - "example" : 82573385 - } - } - }, - "ReleaseType" : { - "default" : "ga", - "enum" : [ "ga", "ea" ], - "type" : "string" - }, - "SortMethod" : { - "description" : "DEFAULT sort order is by: version, then date, then name, then id. DATE sorts by date, then version, then name, then id.", - "default" : "DEFAULT", - "enum" : [ "DEFAULT", "DATE" ], - "type" : "string" - }, - "SortOrder" : { - "default" : "DESC", - "enum" : [ "ASC", "DESC" ], - "type" : "string" - }, - "SourcePackage" : { - "required" : [ "name", "link" ], - "type" : "object", - "properties" : { - "name" : { - "type" : "string", - "example" : "OpenJDK8U-sources_8u232b09.tar.gz" - }, - "link" : { - "type" : "string", - "example" : "https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u232-b09/OpenJDK8U-sources_8u232b09.tar.gz" - }, - "size" : { - "format" : "int64", - "type" : "integer", - "example" : 82573385 - } - } - }, - "StatsSource" : { - "default" : "all", - "enum" : [ "github", "dockerhub", "all" ], - "type" : "string", - "example" : "all" - }, - "Vendor" : { - "$ref" : "#/components/schemas/AdoptiumVendor" - }, - "VersionData" : { - "required" : [ "semver", "openjdk_version" ], - "type" : "object", - "properties" : { - "major" : { - "format" : "int32", - "type" : "integer" - }, - "minor" : { - "format" : "int32", - "type" : "integer" - }, - "security" : { - "format" : "int32", - "type" : "integer" - }, - "patch" : { - "format" : "int32", - "type" : "integer", - "nullable" : true - }, - "pre" : { - "type" : "string", - "nullable" : true - }, - "adopt_build_number" : { - "format" : "int32", - "type" : "integer", - "nullable" : true - }, - "semver" : { - "type" : "string", - "example" : "11.0.0+28" - }, - "openjdk_version" : { - "type" : "string", - "example" : "11.0.4+10-201907081820" - }, - "build" : { - "format" : "int32", - "type" : "integer" - }, - "optional" : { - "type" : "string", - "nullable" : true - } - } - }, - "project" : { - "description" : "Project", - "default" : "jdk", - "enum" : [ "jdk", "valhalla", "metropolis", "jfr", "shenandoah" ], - "type" : "string" - } - } - } -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.yaml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.yaml deleted file mode 100644 index a19b7d24e..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/adoptium.yaml +++ /dev/null @@ -1,1381 +0,0 @@ ---- -openapi: 3.0.3 -info: - title: v3 - description: "" - version: 3.0.0 -servers: - - url: https://api.adoptium.net - - url: https://staging-api.adoptium.net -tags: - - name: Assets - - name: Binary - - name: Checksum - - name: Installer - - name: Release Info - - name: Signature - - name: Version -paths: - /v3/assets/feature_releases/{feature_version}/{release_type}: - get: - tags: - - Assets - summary: Returns release information - description: List of information about builds that match the current query - operationId: searchReleases - parameters: - - name: feature_version - in: path - description: "\n

\n Feature release version you wish to download. Feature\ - \ versions are whole numbers e.g. 8,11,16,17,18.\n

\n

\n\ - \ Available Feature versions can be obtained from \n https://api.adoptium.net/v3/info/available_releases\n

\n" - required: true - schema: - default: 8 - type: integer - nullable: true - - name: release_type - in: path - description: |2 - -

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

- required: true - schema: - allOf: - - $ref: '#/components/schemas/ReleaseType' - - nullable: true - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: before - in: query - description: '

Return binaries whose updated_at is before the given date/time. - When a date is given the match is inclusive of the given day.

  • 2020-01-21
  • -
  • 2020-01-21T10:15:30
  • 20200121
  • 2020-12-21T10:15:30Z
  • -
  • 2020-12-21+01:00

' - required: false - schema: - allOf: - - $ref: '#/components/schemas/DateTime' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: heap_size - in: query - description: Heap Size - required: false - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: query - description: JVM Implementation - required: false - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: page - in: query - description: Pagination page number - required: false - schema: - default: 0 - type: integer - nullable: true - - name: page_size - in: query - description: Pagination page size - required: false - schema: - default: 10 - maximum: 20 - type: integer - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - - name: sort_method - in: query - description: Result sort method - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortMethod' - - nullable: true - - name: sort_order - in: query - description: Result sort order - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortOrder' - - nullable: true - - name: vendor - in: query - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: false - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - responses: - "200": - description: search results matching criteria - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Release' - "400": - description: bad input parameter - /v3/assets/latest/{feature_version}/{jvm_impl}: - get: - tags: - - Assets - summary: Returns list of latest assets for the given feature version and jvm - impl - operationId: getLatestAssets - parameters: - - name: feature_version - in: path - description: "\n

\n Feature release version you wish to download. Feature\ - \ versions are whole numbers e.g. 8,11,16,17,18.\n

\n

\n\ - \ Available Feature versions can be obtained from \n https://api.adoptium.net/v3/info/available_releases\n

\n" - required: true - schema: - default: 8 - type: integer - - name: jvm_impl - in: path - description: JVM Implementation - required: true - schema: - $ref: '#/components/schemas/JvmImpl' - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: vendor - in: query - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: false - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - responses: - "200": - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/BinaryAssetView' - /v3/assets/release_name/{vendor}/{release_name}: - get: - tags: - - Assets - summary: Returns release information - description: List of releases with the given release name - operationId: getReleaseInfo - parameters: - - name: release_name - in: path - description: 'Name of the release i.e ' - required: true - schema: - type: string - nullable: true - - name: vendor - in: path - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: true - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: heap_size - in: query - description: Heap Size - required: false - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: query - description: JVM Implementation - required: false - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - responses: - "200": - description: Release with the given vendor and name - content: - application/json: - schema: - $ref: '#/components/schemas/Release' - "400": - description: bad input parameter - "404": - description: no releases match the request - "500": - description: multiple releases match the request - /v3/assets/version/{version}: - get: - tags: - - Assets - summary: Returns release information about the specified version. - description: 'List of information about builds that match the current query ' - operationId: searchReleasesByVersion - parameters: - - name: version - in: path - description: |2 - - Java version range (maven style) of versions to include. - - e.g: - * `11.0.4.1+11.1` - * `[1.0,2.0)` - * `(,1.0]` - - Details of maven version ranges can be found at - - required: true - schema: - type: string - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: heap_size - in: query - description: Heap Size - required: false - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: query - description: JVM Implementation - required: false - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: lts - in: query - description: Include only LTS releases - required: false - schema: - type: boolean - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: page - in: query - description: Pagination page number - required: false - schema: - default: 0 - type: integer - nullable: true - - name: page_size - in: query - description: Pagination page size - required: false - schema: - default: 10 - maximum: 20 - type: integer - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - - name: release_type - in: query - description: |2 - -

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

- required: false - schema: - allOf: - - $ref: '#/components/schemas/ReleaseType' - - nullable: true - - name: semver - in: query - description: Indicates that any version arguments provided in this request - were Adoptium semantic versions - required: false - schema: - default: false - type: boolean - nullable: true - - name: sort_method - in: query - description: Result sort method - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortMethod' - - nullable: true - - name: sort_order - in: query - description: Result sort order - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortOrder' - - nullable: true - - name: vendor - in: query - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: false - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - responses: - "200": - description: search results matching criteria - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Release' - "400": - description: bad input parameter - /v3/checksum/version/{release_name}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}: - get: - tags: - - Checksum - summary: Redirects to the checksum of the release that matches your current - query - description: Redirects to the checksum of the release that matches your current - query - operationId: getChecksumByVersion - parameters: - - name: arch - in: path - description: Architecture - required: true - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: heap_size - in: path - description: Heap Size - required: true - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: path - description: Image Type - required: true - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: path - description: JVM Implementation - required: true - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: os - in: path - description: Operating System - required: true - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: release_name - in: path - description: "\n

\n Name of the release as displayed in github or https://adoptopenjdk.net/ e.g\n\ - \ jdk-11.0.4+11, jdk8u172-b00-201807161800.\n

\n

\n\ - \ A list of release names can be obtained from \n https://api.adoptium.net/v3/info/release_names\n

\n" - required: true - schema: - default: jdk-11.0.6+10 - type: string - nullable: true - - name: vendor - in: path - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: true - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - responses: - "307": - description: link to checksum of the release that matches your current query - "400": - description: bad input parameter - "404": - description: No matching signature found - /v3/info/available_releases: - get: - tags: - - Release Info - summary: Returns information about available releases - operationId: getAvailableReleases - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ReleaseInfo' - /v3/info/release_names: - get: - tags: - - Release Info - summary: Returns a list of all release names - operationId: getReleaseNames - parameters: - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: heap_size - in: query - description: Heap Size - required: false - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: query - description: JVM Implementation - required: false - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: lts - in: query - description: Include only LTS releases - required: false - schema: - type: boolean - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: page - in: query - description: Pagination page number - required: false - schema: - default: 0 - type: integer - nullable: true - - name: page_size - in: query - description: Pagination page size - required: false - schema: - default: 10 - maximum: 20 - type: integer - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - - name: release_type - in: query - description: |2 - -

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

- required: false - schema: - allOf: - - $ref: '#/components/schemas/ReleaseType' - - nullable: true - - name: semver - in: query - description: Indicates that any version arguments provided in this request - were Adoptium semantic versions - required: false - schema: - default: false - type: boolean - nullable: true - - name: sort_method - in: query - description: Result sort method - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortMethod' - - nullable: true - - name: sort_order - in: query - description: Result sort order - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortOrder' - - nullable: true - - name: vendor - in: query - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: false - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - - name: version - in: query - description: |2 - - Java version range (maven style) of versions to include. - - e.g: - * `11.0.4.1+11.1` - * `[1.0,2.0)` - * `(,1.0]` - - Details of maven version ranges can be found at - - required: false - schema: - type: string - nullable: true - responses: - "200": - description: A list of all release names - content: - application/json: - schema: - required: - - releases - type: object - properties: - releases: - type: array - items: - type: string - /v3/info/release_versions: - get: - tags: - - Release Info - summary: Returns a list of all release versions - operationId: getReleaseVersions - parameters: - - name: architecture - in: query - description: Architecture - required: false - schema: - allOf: - - $ref: '#/components/schemas/Architecture' - - nullable: true - - name: c_lib - in: query - description: "C Lib type, typically would imply image_type has been set to\ - \ staticlibs" - required: false - schema: - allOf: - - $ref: '#/components/schemas/CLib' - - nullable: true - - name: heap_size - in: query - description: Heap Size - required: false - schema: - allOf: - - $ref: '#/components/schemas/HeapSize' - - nullable: true - - name: image_type - in: query - description: Image Type - required: false - schema: - allOf: - - $ref: '#/components/schemas/ImageType' - - nullable: true - - name: jvm_impl - in: query - description: JVM Implementation - required: false - schema: - allOf: - - $ref: '#/components/schemas/JvmImpl' - - nullable: true - - name: lts - in: query - description: Include only LTS releases - required: false - schema: - type: boolean - nullable: true - - name: os - in: query - description: Operating System - required: false - schema: - allOf: - - $ref: '#/components/schemas/OperatingSystem' - - nullable: true - - name: page - in: query - description: Pagination page number - required: false - schema: - default: 0 - type: integer - nullable: true - - name: page_size - in: query - description: Pagination page size - required: false - schema: - default: 10 - maximum: 50 - type: integer - nullable: true - - name: project - in: query - description: Project - required: false - schema: - allOf: - - $ref: '#/components/schemas/project' - - nullable: true - - name: release_type - in: query - description: |2 - -

Type of release. Either a release version, known as General Availability(ga) or an Early Access(ea)

- required: false - schema: - allOf: - - $ref: '#/components/schemas/ReleaseType' - - nullable: true - - name: semver - in: query - description: Indicates that any version arguments provided in this request - were Adoptium semantic versions - required: false - schema: - default: false - type: boolean - nullable: true - - name: sort_method - in: query - description: Result sort method - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortMethod' - - nullable: true - - name: sort_order - in: query - description: Result sort order - required: false - schema: - allOf: - - $ref: '#/components/schemas/SortOrder' - - nullable: true - - name: vendor - in: query - description:

Vendor of the binary. This is the organisation that produced - the binary package.

- required: false - schema: - allOf: - - $ref: '#/components/schemas/Vendor' - - nullable: true - - name: version - in: query - description: |2 - - Java version range (maven style) of versions to include. - - e.g: - * `11.0.4.1+11.1` - * `[1.0,2.0)` - * `(,1.0]` - - Details of maven version ranges can be found at - - required: false - schema: - type: string - nullable: true - responses: - "200": - description: A list of all release versions - content: - application/json: - schema: - required: - - versions - type: object - properties: - versions: - type: array - items: - $ref: '#/components/schemas/VersionData' - /v3/version/{version}: - get: - tags: - - Version - summary: Parses a java version string - description: Parses a java version string and returns that data in a structured - format - operationId: parseVersion - parameters: - - name: version - in: path - description: Version - required: true - schema: - type: string - nullable: true - responses: - "400": - description: bad input parameter -components: - schemas: - AdoptiumJvmImpl: - enum: - - hotspot - type: string - AdoptiumVendor: - default: eclipse - enum: - - eclipse - type: string - example: eclipse - Architecture: - enum: - - x64 - - x86 - - x32 - - ppc64 - - ppc64le - - s390x - - aarch64 - - arm - - sparcv9 - - riscv64 - type: string - Binary: - required: - - os - - architecture - - image_type - - jvm_impl - - heap_size - - updated_at - - project - type: object - properties: - os: - $ref: '#/components/schemas/OperatingSystem' - architecture: - $ref: '#/components/schemas/Architecture' - image_type: - $ref: '#/components/schemas/ImageType' - c_lib: - type: string - allOf: - - $ref: '#/components/schemas/CLib' - nullable: true - jvm_impl: - $ref: '#/components/schemas/JvmImpl' - package: - $ref: '#/components/schemas/Package' - installer: - $ref: '#/components/schemas/Installer' - heap_size: - $ref: '#/components/schemas/HeapSize' - download_count: - format: int64 - type: integer - example: 3899 - updated_at: - $ref: '#/components/schemas/DateTime' - scm_ref: - type: string - example: dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93 - nullable: true - project: - $ref: '#/components/schemas/project' - BinaryAssetView: - required: - - release_name - - release_link - type: object - properties: - binary: - $ref: '#/components/schemas/Binary' - release_name: - type: string - example: jdk8u162-b12_openj9-0.8.0 - release_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/tag/jdk8u162-b12_openj9-0.8.0 - vendor: - $ref: '#/components/schemas/Vendor' - version: - $ref: '#/components/schemas/VersionData' - CLib: - enum: - - musl - - glibc - type: string - DateTime: - description:

Date/time. When only a date is given the time is set to the - end of the given day.

  • 2020-01-21
  • 2020-01-21T10:15:30
  • -
  • 20200121
  • 2020-12-21T10:15:30Z
  • 2020-12-21+01:00
  • -

- type: string - HeapSize: - enum: - - normal - - large - type: string - example: normal - ImageType: - enum: - - jdk - - jre - - testimage - - debugimage - - staticlibs - - sources - - sbom - type: string - example: jdk - Installer: - required: - - name - - link - type: object - properties: - name: - type: string - example: OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi - link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-binaries/ga/download/jdk8u212-b04/OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi - size: - format: int64 - type: integer - example: 82573385 - checksum: - type: string - example: dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93 - nullable: true - checksum_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.sha256.txt - nullable: true - signature_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jdk_x64_linux_11.0.5_10.tar.gz.sign - nullable: true - download_count: - format: int64 - type: integer - example: 2 - metadata_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.json - nullable: true - JvmImpl: - $ref: '#/components/schemas/AdoptiumJvmImpl' - OperatingSystem: - enum: - - linux - - windows - - mac - - solaris - - aix - - alpine-linux - type: string - Package: - required: - - name - - link - type: object - properties: - name: - type: string - example: OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi - link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-binaries/ga/download/jdk8u212-b04/OpenJDK8U-jre_x86-32_windows_hotspot_8u212b04.msi - size: - format: int64 - type: integer - example: 82573385 - checksum: - type: string - example: dd28d6d2cde2b931caf94ac2422a2ad082ea62f0beee3bf7057317c53093de93 - nullable: true - checksum_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.sha256.txt - nullable: true - signature_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jdk_x64_linux_11.0.5_10.tar.gz.sign - nullable: true - download_count: - format: int64 - type: integer - example: 2 - metadata_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/download/jdk8u162-b12_openj9-0.8.0/OpenJDK8-OPENJ9_x64_Linux_jdk8u162-b12_openj9-0.8.0.tar.gz.json - nullable: true - Release: - required: - - id - - release_link - - release_name - - timestamp - - updated_at - - binaries - - release_type - - vendor - - version_data - type: object - properties: - id: - type: string - example: VXNlci0xMA== - release_link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-openj9-releases/ga/tag/jdk8u162-b12_openj9-0.8.0 - release_name: - type: string - example: jdk8u162-b12_openj9-0.8.0 - timestamp: - $ref: '#/components/schemas/DateTime' - updated_at: - $ref: '#/components/schemas/DateTime' - binaries: - type: array - items: - $ref: '#/components/schemas/Binary' - download_count: - format: int64 - type: integer - example: 7128 - release_type: - $ref: '#/components/schemas/ReleaseType' - vendor: - $ref: '#/components/schemas/Vendor' - version_data: - $ref: '#/components/schemas/VersionData' - source: - type: object - allOf: - - $ref: '#/components/schemas/SourcePackage' - nullable: true - release_notes: - type: object - allOf: - - $ref: '#/components/schemas/ReleaseNotesPackage' - nullable: true - aqavit_results_link: - type: string - example: https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6%2B10/AQAvitTapFiles.tar.gz - nullable: true - ReleaseInfo: - required: - - available_releases - - available_lts_releases - type: object - properties: - available_releases: - description: The versions for which adopt have produced a ga release - type: array - items: - format: int32 - type: integer - example: - - 8 - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - available_lts_releases: - description: The LTS versions for which adopt have produced a ga release - type: array - items: - format: int32 - type: integer - example: - - 8 - - 11 - most_recent_lts: - format: int32 - description: The highest LTS version for which adopt have produced a ga - release - type: integer - example: 11 - most_recent_feature_release: - format: int32 - description: The highest version (LTS or not) for which adopt have produced - a ga release - type: integer - example: 13 - most_recent_feature_version: - format: int32 - description: "The highest version (LTS or not) for which we have produced\ - \ a build, this may be a version that has not yet produced a ga release" - type: integer - example: 15 - tip_version: - format: int32 - description: The version that is currently in development at openjdk - type: integer - example: 15 - ReleaseNote: - required: - - id - type: object - properties: - id: - type: string - title: - type: string - nullable: true - priority: - type: string - nullable: true - component: - type: string - nullable: true - subcomponent: - type: string - nullable: true - link: - type: string - nullable: true - type: - type: string - nullable: true - backportOf: - type: string - nullable: true - ReleaseNotesPackage: - required: - - name - - link - type: object - properties: - name: - type: string - example: OpenJDK8U-sources_8u232b09.tar.gz - link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u232-b09/OpenJDK8U-sources_8u232b09.tar.gz - size: - format: int64 - type: integer - example: 82573385 - ReleaseType: - default: ga - enum: - - ga - - ea - type: string - SortMethod: - description: "DEFAULT sort order is by: version, then date, then name, then\ - \ id. DATE sorts by date, then version, then name, then id." - default: DEFAULT - enum: - - DEFAULT - - DATE - type: string - SortOrder: - default: DESC - enum: - - ASC - - DESC - type: string - SourcePackage: - required: - - name - - link - type: object - properties: - name: - type: string - example: OpenJDK8U-sources_8u232b09.tar.gz - link: - type: string - example: https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u232-b09/OpenJDK8U-sources_8u232b09.tar.gz - size: - format: int64 - type: integer - example: 82573385 - StatsSource: - default: all - enum: - - github - - dockerhub - - all - type: string - example: all - Vendor: - $ref: '#/components/schemas/AdoptiumVendor' - VersionData: - required: - - semver - - openjdk_version - type: object - properties: - major: - format: int32 - type: integer - minor: - format: int32 - type: integer - security: - format: int32 - type: integer - patch: - format: int32 - type: integer - nullable: true - pre: - type: string - nullable: true - adopt_build_number: - format: int32 - type: integer - nullable: true - semver: - type: string - example: 11.0.0+28 - openjdk_version: - type: string - example: 11.0.4+10-201907081820 - build: - format: int32 - type: integer - optional: - type: string - nullable: true - project: - description: Project - default: jdk - enum: - - jdk - - valhalla - - metropolis - - jfr - - shenandoah - type: string diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/authenticatedRequest.yaml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/authenticatedRequest.yaml deleted file mode 100644 index b38ea8d2c..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/authenticatedRequest.yaml +++ /dev/null @@ -1,25 +0,0 @@ -openapi: 3.0.2 -servers: - - url: / -info: - description: |- - Example of an authenticated api - version: 1.0.1-SNAPSHOT - title: Auth Example -paths: - /state: - get: - summary: Get the latest state of the system - description: The current state the system - operationId: getState - responses: - '200': - description: The current state of the system - security: - - BearerAuth: - - 'read' -components: - securitySchemes: - BearerAuth: - type: http - scheme: bearer diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/log4j2.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/log4j2.xml deleted file mode 100644 index 50a638f0d..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/petstore.yaml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/petstore.yaml deleted file mode 100644 index 29a3432ce..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/src/test/resources/petstore.yaml +++ /dev/null @@ -1,822 +0,0 @@ -# Sample from: Swagger - https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml -# Under Apache 2.0 License ---- -openapi: 3.0.2 -servers: - - url: /v3 -info: - description: |- - This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about - Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! - You can now help us improve the API whether it's by making changes to the definition itself or to the code. - That way, with time, we can improve the API in general, and expose some of the new features in OAS3. - - Some useful links: - - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) - version: 1.0.20-SNAPSHOT - title: Swagger Petstore - OpenAPI 3.0 - termsOfService: 'http://swagger.io/terms/' - contact: - email: apiteam@swagger.io - license: - name: Apache 2.0 - url: 'http://www.apache.org/licenses/LICENSE-2.0.html' -tags: - - name: pet - description: Everything about your Pets - externalDocs: - description: Find out more - url: 'http://swagger.io' - - name: store - description: Access to Petstore orders - externalDocs: - description: Find out more about our store - url: 'http://swagger.io' - - name: user - description: Operations about user -paths: - /pet: - post: - tags: - - pet - summary: Add a new pet to the store - description: Add a new pet to the store - operationId: addPet - responses: - '200': - description: Successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '405': - description: Invalid input - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - requestBody: - description: Create a new pet in the store - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - put: - tags: - - pet - summary: Update an existing pet - description: Update an existing pet by Id - operationId: updatePet - responses: - '200': - description: Successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - '405': - description: Validation exception - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - requestBody: - description: Update an existent pet in the store - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - /pet/findByStatus: - get: - tags: - - pet - summary: Finds Pets by status - description: Multiple status values can be provided with comma separated strings - operationId: findPetsByStatus - parameters: - - name: status - in: query - description: Status values that need to be considered for filter - required: false - explode: true - schema: - type: string - enum: - - available - - pending - - sold - default: available - responses: - '200': - description: successful operation - content: - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid status value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - /pet/findByTags: - get: - tags: - - pet - summary: Finds Pets by tags - description: >- - Multiple tags can be provided with comma separated strings. Use tag1, - tag2, tag3 for testing. - operationId: findPetsByTags - parameters: - - name: tags - in: query - description: Tags to filter by - required: false - explode: true - schema: - type: array - items: - type: string - responses: - '200': - description: successful operation - content: - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid tag value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - '/pet/{petId}': - get: - tags: - - pet - summary: Find pet by ID - description: Returns a single pet - operationId: getPetById - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - api_key: [] - - petstore_auth: - - 'write:pets' - - 'read:pets' - post: - tags: - - pet - summary: Updates a pet in the store with form data - description: '' - operationId: updatePetWithForm - parameters: - - name: petId - in: path - description: ID of pet that needs to be updated - required: true - schema: - type: integer - format: int64 - - name: name - in: query - description: Name of pet that needs to be updated - schema: - type: string - - name: status - in: query - description: Status of pet that needs to be updated - schema: - type: string - responses: - '405': - description: Invalid input - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - delete: - tags: - - pet - summary: Deletes a pet - description: '' - operationId: deletePet - parameters: - - name: api_key - in: header - description: '' - required: false - schema: - type: string - - name: petId - in: path - description: Pet id to delete - required: true - schema: - type: integer - format: int64 - responses: - '400': - description: Invalid pet value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - '/pet/{petId}/uploadImage': - post: - tags: - - pet - summary: uploads an image - description: '' - operationId: uploadFile - parameters: - - name: petId - in: path - description: ID of pet to update - required: true - schema: - type: integer - format: int64 - - name: additionalMetadata - in: query - description: Additional Metadata - required: false - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - requestBody: - content: - application/octet-stream: - schema: - type: string - format: binary - /store/inventory: - get: - tags: - - store - summary: Returns pet inventories by status - description: Returns a map of status codes to quantities - operationId: getInventory - x-swagger-router-controller: OrderController - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: object - additionalProperties: - type: integer - format: int32 - security: - - api_key: [] - /store/order: - post: - tags: - - store - summary: Place an order for a pet - description: Place a new order in the store - operationId: placeOrder - x-swagger-router-controller: OrderController - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '405': - description: Invalid input - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Order' - '/store/order/{orderId}': - get: - tags: - - store - summary: Find purchase order by ID - x-swagger-router-controller: OrderController - description: >- - For valid response try integer IDs with value <= 5 or > 10. Other values - will generate exceptions. - operationId: getOrderById - parameters: - - name: orderId - in: path - description: ID of order that needs to be fetched - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid ID supplied - '404': - description: Order not found - delete: - tags: - - store - summary: Delete purchase order by ID - x-swagger-router-controller: OrderController - description: >- - For valid response try integer IDs with value < 1000. Anything above - 1000 or nonintegers will generate API errors - operationId: deleteOrder - parameters: - - name: orderId - in: path - description: ID of the order that needs to be deleted - required: true - schema: - type: integer - format: int64 - responses: - '400': - description: Invalid ID supplied - '404': - description: Order not found - /user: - post: - tags: - - user - summary: Create user - description: This can only be done by the logged in user. - operationId: createUser - responses: - default: - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - description: Created user object - /user/createWithList: - post: - tags: - - user - summary: Creates list of users with given input array - description: 'Creates list of users with given input array' - x-swagger-router-controller: UserController - operationId: createUsersWithListInput - responses: - '200': - description: Successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/User' - application/json: - schema: - $ref: '#/components/schemas/User' - default: - description: successful operation - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - /user/login: - get: - tags: - - user - summary: Logs user into the system - description: '' - operationId: loginUser - parameters: - - name: username - in: query - description: The user name for login - required: false - schema: - type: string - - name: password - in: query - description: The password for login in clear text - required: false - schema: - type: string - responses: - '200': - description: successful operation - headers: - X-Rate-Limit: - description: calls per hour allowed by the user - schema: - type: integer - format: int32 - X-Expires-After: - description: date in UTC when token expires - schema: - type: string - format: date-time - content: - application/xml: - schema: - type: string - application/json: - schema: - type: string - '400': - description: Invalid username/password supplied - /user/logout: - get: - tags: - - user - summary: Logs out current logged in user session - description: '' - operationId: logoutUser - parameters: [] - responses: - default: - description: successful operation - '/user/{username}': - get: - tags: - - user - summary: Get user by user name - description: '' - operationId: getUserByName - parameters: - - name: username - in: path - description: 'The name that needs to be fetched. Use user1 for testing. ' - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/User' - application/json: - schema: - $ref: '#/components/schemas/User' - '400': - description: Invalid username supplied - '404': - description: User not found - put: - tags: - - user - summary: Update user - x-swagger-router-controller: UserController - description: This can only be done by the logged in user. - operationId: updateUser - parameters: - - name: username - in: path - description: name that needs to be updated - required: true - schema: - type: string - responses: - default: - description: successful operation - requestBody: - description: Update an existent user in the store - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - delete: - tags: - - user - summary: Delete user - description: This can only be done by the logged in user. - operationId: deleteUser - parameters: - - name: username - in: path - description: The name that needs to be deleted - required: true - schema: - type: string - responses: - '400': - description: Invalid username supplied - '404': - description: User not found -externalDocs: - description: Find out more about Swagger - url: 'http://swagger.io' -components: - schemas: - Order: - x-swagger-router-model: io.swagger.petstore.model.Order - properties: - id: - type: integer - format: int64 - example: 10 - petId: - type: integer - format: int64 - example: 198772 - quantity: - type: integer - format: int32 - example: 7 - shipDate: - type: string - format: date-time - status: - type: string - description: Order Status - enum: - - placed - - approved - - delivered - example: approved - complete: - type: boolean - xml: - name: order - type: object - Customer: - properties: - id: - type: integer - format: int64 - example: 100000 - username: - type: string - example: fehguy - address: - type: array - items: - $ref: '#/components/schemas/Address' - xml: - wrapped: true - name: addresses - xml: - name: customer - type: object - Address: - properties: - street: - type: string - example: 437 Lytton - city: - type: string - example: Palo Alto - state: - type: string - example: CA - zip: - type: string - example: 94301 - xml: - name: address - type: object - Category: - x-swagger-router-model: io.swagger.petstore.model.Category - properties: - id: - type: integer - format: int64 - example: 1 - name: - type: string - example: Dogs - xml: - name: category - type: object - User: - x-swagger-router-model: io.swagger.petstore.model.User - properties: - id: - type: integer - format: int64 - example: 10 - username: - type: string - example: theUser - firstName: - type: string - example: John - lastName: - type: string - example: James - email: - type: string - example: john@email.com - password: - type: string - example: 12345 - phone: - type: string - example: 12345 - userStatus: - type: integer - format: int32 - example: 1 - description: User Status - xml: - name: user - type: object - Tag: - x-swagger-router-model: io.swagger.petstore.model.Tag - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: tag - type: object - Pet: - x-swagger-router-model: io.swagger.petstore.model.Pet - required: - - name - - photoUrls - properties: - id: - type: integer - format: int64 - example: 10 - name: - type: string - example: doggie - category: - $ref: '#/components/schemas/Category' - photoUrls: - type: array - xml: - wrapped: true - items: - type: string - xml: - name: photoUrl - tags: - type: array - xml: - wrapped: true - items: - $ref: '#/components/schemas/Tag' - xml: - name: tag - status: - type: string - description: pet status in the store - enum: - - available - - pending - - sold - xml: - name: pet - type: object - ApiResponse: - properties: - code: - type: integer - format: int32 - type: - type: string - message: - type: string - xml: - name: '##default' - type: object - requestBodies: - Pet: - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - description: Pet object that needs to be added to the store - UserArray: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - description: List of user object - securitySchemes: - petstore_auth: - type: oauth2 - flows: - implicit: - authorizationUrl: 'http://localhost:8123/oauth/authorize' - scopes: - 'write:pets': modify pets in your account - 'read:pets': read your pets - api_key: - type: apiKey - name: api_key - in: header diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml deleted file mode 100644 index 10326e6ea..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-presidio-plugin - semantickernel-presidio-plugin - jar - - - - - com.microsoft.semantic-kernel - semantickernel-bom - ${project.version} - pom - import - - - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - - org.apache.logging.log4j - log4j-api - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.azure - azure-identity - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - bug-check - - - false - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - true - - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - - - - org.codehaus.mojo - exec-maven-plugin - - - run-sample - - java - - - - - com.microsoft.semantickernel.samples.syntaxexamples.${sample} - - - - - diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedText.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedText.java deleted file mode 100644 index 6de328b66..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedText.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import java.util.Collections; -import java.util.Map; - -public class AnonymizedText { - - private final String unRedacted; - private final String redacted; - private final Map redactedTokenMap; - - public AnonymizedText( - String unRedacted, - String redacted, - Map redactedTokenMap) { - this.unRedacted = unRedacted; - this.redacted = redacted; - this.redactedTokenMap = Collections.unmodifiableMap(redactedTokenMap); - } - - public String getUnRedacted() { - return unRedacted; - } - - public String getRedacted() { - return redacted; - } - - public Map getRedactedTokenMap() { - return redactedTokenMap; - } - - public String unredact(String message) { - return redactedTokenMap - .entrySet() - .stream() - .reduce(message, - (msg, entry) -> msg.replaceAll(entry.getKey(), entry.getValue()), - (msg1, msg2) -> msg1 + msg2); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedTextConverter.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedTextConverter.java deleted file mode 100644 index ab00fed95..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/AnonymizedTextConverter.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; - -public class AnonymizedTextConverter extends ContextVariableTypeConverter { - - public AnonymizedTextConverter() { - super( - AnonymizedText.class, - it -> (AnonymizedText) it, - AnonymizedText::getRedacted, - text -> { - throw new UnsupportedOperationException("AnonymizedText is write-only"); - }); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnalysisClient.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnalysisClient.java deleted file mode 100644 index d9e678050..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnalysisClient.java +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import com.azure.core.http.ContentType; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.HttpMethod; -import com.azure.core.http.HttpRequest; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.microsoft.semantickernel.presidio.models.AnalyzerRequest; -import com.microsoft.semantickernel.presidio.models.AnalyzerResult; -import java.net.URL; -import java.util.List; -import reactor.core.publisher.Mono; - -public class PresidioAnalysisClient extends PresidioApiClient { - - public PresidioAnalysisClient( - HttpClient client, - URL endpoint) { - super(client, endpoint); - } - - public Mono> analyze(AnalyzerRequest analyzerRequest) { - try { - HttpRequest request = new HttpRequest(HttpMethod.POST, - new URL(super.endpoint, "/analyze")) - .setHeader(HttpHeaderName.CONTENT_TYPE, ContentType.APPLICATION_JSON) - .setBody(super.mapper.writeValueAsBytes(analyzerRequest)); - - return super.client.send(request) - .flatMap(httpResponse -> { - if (httpResponse.getStatusCode() != 200) { - return Mono.error( - new RuntimeException( - "Request failed: " + httpResponse.getStatusCode())); - } else { - return httpResponse.getBodyAsString(); - } - }) - .flatMap(body -> { - try { - TypeReference> type = new TypeReference<>() { - }; - - return Mono.just(mapper.readValue(body, type)); - } catch (JsonProcessingException e) { - return Mono.error( - new RuntimeException("Failed to parse response", e)); - } - }); - } catch (Exception e) { - return Mono.error(e); - } - } - - public Mono> analyze(String text, String language) { - return analyze(new AnalyzerRequest(text, language)); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnonmizerClient.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnonmizerClient.java deleted file mode 100644 index fa4979ad1..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioAnonmizerClient.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import com.azure.core.http.ContentType; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpHeaderName; -import com.azure.core.http.HttpMethod; -import com.azure.core.http.HttpRequest; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.microsoft.semantickernel.presidio.models.AnalyzerResult; -import com.microsoft.semantickernel.presidio.models.AnonymizeRequest; -import com.microsoft.semantickernel.presidio.models.AnonymizerResult; -import com.microsoft.semantickernel.presidio.models.anonymizerType.AnonymizerType; -import java.net.URL; -import java.util.List; -import java.util.Map; -import reactor.core.publisher.Mono; - -public class PresidioAnonmizerClient extends PresidioApiClient { - - public PresidioAnonmizerClient( - HttpClient client, - URL endpoint) { - super(client, endpoint); - } - - public Mono anonymize(String text, - Map anonymizers, - List analyzerResults) { - - return anonymize(new AnonymizeRequest(text, anonymizers, analyzerResults)); - } - - private Mono anonymize(AnonymizeRequest anonymizeRequest) { - - try { - HttpRequest request = new HttpRequest(HttpMethod.POST, - new URL(super.endpoint, "/anonymize")) - .setHeader(HttpHeaderName.CONTENT_TYPE, ContentType.APPLICATION_JSON) - .setBody(super.mapper.writeValueAsBytes(anonymizeRequest)); - - return super.client.send(request) - .flatMap(httpResponse -> { - if (httpResponse.getStatusCode() >= 400) { - return Mono.error( - new RuntimeException( - "Request failed: " + httpResponse.getStatusCode())); - } else { - return httpResponse.getBodyAsString(); - } - }) - .flatMap(body -> { - try { - TypeReference type = new TypeReference<>() { - }; - - return Mono.just(mapper.readValue(body, type)); - } catch (JsonProcessingException e) { - return Mono.error( - new RuntimeException("Failed to parse response", e)); - } - }); - } catch (Exception e) { - return Mono.error(e); - } - - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioApiClient.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioApiClient.java deleted file mode 100644 index 8f2ea06ce..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/PresidioApiClient.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import com.azure.core.http.HttpClient; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.net.URL; - -public abstract class PresidioApiClient { - - protected final HttpClient client; - protected final URL endpoint; - protected final ObjectMapper mapper; - - public PresidioApiClient( - HttpClient client, - URL endpoint) { - this.client = client; - this.endpoint = endpoint; - this.mapper = new ObjectMapper(); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/RedactorPlugin.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/RedactorPlugin.java deleted file mode 100644 index a8e156b47..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/RedactorPlugin.java +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio; - -import com.azure.core.http.HttpClient; -import com.microsoft.semantickernel.presidio.models.AnalyzerResult; -import com.microsoft.semantickernel.presidio.models.anonymizerType.AnonymizerType.Replace; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.semanticfunctions.annotations.SKSample; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -public class RedactorPlugin { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedactorPlugin.class); - - private final PresidioAnalysisClient analysisClient; - - private final PresidioAnonmizerClient anonymizeClient; - - public RedactorPlugin( - String analysisServer, - String anonymizeServer) { - URL analysisUrl = null; - try { - analysisUrl = URI.create(analysisServer).toURL(); - } catch (MalformedURLException e) { - LOGGER.error("Failed to parse url", e); - } - - analysisClient = new PresidioAnalysisClient( - HttpClient.createDefault(), - analysisUrl); - - URL anonymizeUrl = null; - try { - anonymizeUrl = URI.create(anonymizeServer).toURL(); - } catch (MalformedURLException e) { - LOGGER.error("Failed to parse url", e); - } - - anonymizeClient = new PresidioAnonmizerClient( - HttpClient.createDefault(), - anonymizeUrl); - } - - @DefineKernelFunction(name = "redact", description = "Takes a string of data and redacts sensitive data from that text.", returnType = "com.microsoft.semantickernel.presidio.AnonymizedText", returnDescription = "The redacted text", samples = { - @SKSample(inputs = "Bob is tall.", output = "PERSON1 is tall.") - }) - public Mono redactData( - @KernelFunctionParameter(name = "input", description = "Text to be redacted") String text) { - return analysisClient - .analyze(text, "en") - .flatMap(analysisResult -> { - Map> grouped = groupResultsByAnonymizedData( - analysisResult, text); - - Map requestMaps = formAnonymizersMap(grouped); - - List allAnalyses = collectAllAnalyses(grouped); - - return anonymizeClient - .anonymize(text, requestMaps, allAnalyses) - .map(redacted -> { - Map anonymizedTokenMap = formAnonymizedTokenMap(grouped); - - return new AnonymizedText( - text, - redacted.text(), - anonymizedTokenMap); - }); - }); - - } - - private static Map formAnonymizedTokenMap( - Map> grouped) { - return grouped - .entrySet() - .stream() - .collect(Collectors.toMap( - entry -> entry.getValue().get(0).entityType(), - Entry::getKey)); - } - - private static List collectAllAnalyses( - Map> grouped) { - return grouped.values() - .stream() - .flatMap(Collection::stream) - .toList(); - } - - private static Map formAnonymizersMap( - Map> grouped) { - return grouped - .entrySet() - .stream() - .collect(Collectors.toMap( - entry -> entry.getValue().get(0).entityType(), - entry -> new Replace(entry.getValue().get(0).entityType()))); - } - - private static Map> groupResultsByAnonymizedData( - List analysisResult, String text) { - Map> grouped = analysisResult - .stream() - .collect(Collectors.groupingBy( - analyzerResult -> text.substring(analyzerResult.start(), - analyzerResult.end()))); - - AtomicInteger count = new AtomicInteger(0); - grouped = grouped - .entrySet() - .stream() - .collect(Collectors.toMap(Entry::getKey, - entry -> { - count.incrementAndGet(); - return entry.getValue().stream().map( - r -> new AnalyzerResult( - r.start(), - r.end(), - r.score(), - r.entityType() + count.get(), - r.recognitionMetadata(), - r.analysisExplanation())) - .toList(); - })); - return grouped; - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalysisExplanation.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalysisExplanation.java deleted file mode 100644 index d135503b1..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalysisExplanation.java +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -public record AnalysisExplanation( - String recognizer, - String pattern_name, - String pattern, - Float original_score, - Float score, - String textual_explanation, - Float score_context_improvement, - String supportive_context_word, - Float validation_result -) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerRequest.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerRequest.java deleted file mode 100644 index e2e28d976..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -public record AnalyzerRequest(String text, String language) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerResult.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerResult.java deleted file mode 100644 index 65adb9ccb..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnalyzerResult.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -import com.fasterxml.jackson.annotation.JsonProperty; - - -public record AnalyzerResult( - Integer start, - Integer end, - Float score, - @JsonProperty("entity_type") - String entityType, - @JsonProperty("recognition_metadata") - RecognitionMetadata recognitionMetadata, - @JsonProperty("analysis_explanation") - AnalysisExplanation analysisExplanation -) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizeRequest.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizeRequest.java deleted file mode 100644 index a3de4d34b..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizeRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.presidio.models.anonymizerType.AnonymizerType; -import java.util.List; -import java.util.Map; - -public record AnonymizeRequest( - String text, - Map anonymizers, - @JsonProperty("analyzer_results") - List analyzerResults) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/Anonymizer.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/Anonymizer.java deleted file mode 100644 index 891b2fdaa..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/Anonymizer.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -public record Anonymizer( - Integer charsToMask, - boolean fromEnd, - String maskingChar, - String type -) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerItem.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerItem.java deleted file mode 100644 index edac21856..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerItem.java +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -public record AnonymizerItem( - String operator, - String entity_type, - String text, - Integer start, - Integer end -) { - -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerResult.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerResult.java deleted file mode 100644 index d601daa25..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/AnonymizerResult.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -import java.util.List; - -public record AnonymizerResult( - String text, - List items) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/RecognitionMetadata.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/RecognitionMetadata.java deleted file mode 100644 index 9d23d963a..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/RecognitionMetadata.java +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public record RecognitionMetadata( - @JsonProperty("recognizer_identifier") - String recognizerIdentifier, - @JsonProperty("recognizer_name") - String recognizerName -) { - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/anonymizerType/AnonymizerType.java b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/anonymizerType/AnonymizerType.java deleted file mode 100644 index 8bb22ee2f..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/src/main/java/com/microsoft/semantickernel/presidio/models/anonymizerType/AnonymizerType.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.presidio.models.anonymizerType; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class AnonymizerType { - - private String type; - - AnonymizerType( - @JsonProperty("type") String type) { - this.type = type; - } - - @JsonProperty("type") - public String getType() { - return type; - } - - public static class Replace extends AnonymizerType { - - private final String new_value; - - @JsonCreator - public Replace( - @JsonProperty("new_value") String new_value) { - super("replace"); - this.new_value = new_value; - } - - @JsonProperty("new_value") - public String getNewValue() { - return new_value; - } - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Chunk.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Chunk.java deleted file mode 100644 index f815656ec..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Chunk.java +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -public class Chunk { - - private final String chunk; - - public Chunk(String chunk) { - this.chunk = chunk; - } - - public String getContents() { - return chunk; - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkEndCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkEndCondition.java deleted file mode 100644 index 536b23527..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkEndCondition.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -/** - * Defines the condition that should be met for a chunk to be considered full. - */ -public interface ChunkEndCondition { - - /** - * Accepts a string and returns the number of character that should be considered as the end of - * the FIRST chunk within the string. This method will be subsequently called until all pages - * are found. - *

- * Return -1 if the value does not contain enough characters to be considered as a full chunk. - * - * @param value the value to be checked - * @return the index of the character that should be considered as the end of the first chunk in - * the string - */ - public int getEndOfNextChunk(String value); - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkPostProcessor.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkPostProcessor.java deleted file mode 100644 index 4a1d19f87..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/ChunkPostProcessor.java +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -/** - * A post processor that processes a chunk after it has been split. - */ -public interface ChunkPostProcessor { - Chunk process(Chunk chunk); -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Document.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Document.java deleted file mode 100644 index 730d27279..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Document.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -import reactor.core.publisher.Flux; - -/** - * A document to be read and split into chunks. - */ -public interface Document { - Flux getContent(); -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/OverlapCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/OverlapCondition.java deleted file mode 100644 index fc8168072..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/OverlapCondition.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -/** - * Defines how much overlap is allowed between two pages. - */ -public interface OverlapCondition { - - /** - * Returns the index of the first character that should be considered as the beginning of the - * overlap. - * - * @param chunk the chunk to be checked - * @return the index of the first character that should be considered as the beginning of the - * overlap - */ - public int getOverlapIndex(String chunk); - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Splitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Splitter.java deleted file mode 100644 index 5e888c526..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/Splitter.java +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -import com.microsoft.semantic.kernel.rag.splitting.overlap.CountOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.overlap.NoOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.overlap.PercentageOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.postprocessors.RemoveWhitespace; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.CountSplitCondition; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.NewLineSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.ParagraphSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SentenceSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.WhiteSpaceFilter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.WordSplitter; -import com.microsoft.semantickernel.exceptions.SKException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; - -/** - * Splits a document into chunks based on supplied chunking strategy. - *

- * The chunking strategies and conditions are somewhat soft limits. In scenarios where trivial - * chunks or tokens would be formed by the chunking strategy (for instance a chunk of only a few - * words would be formed), these will be merged into the previous chunk. As such it is possible that - * the chunks returned may be larger than the specified chunking strategy would imply, after other - * trivial chunks have been merged into them. - */ -public class Splitter { - - private static final Logger LOGGER = LoggerFactory.getLogger(Splitter.class.getName()); - - private final List chunkEndConditions; - private final OverlapCondition overlapCondition; - private final TrivialChunkFilter trivialChunkFilter; - private final ChunkPostProcessor chunkPostProcessor; - - public Splitter( - List chunkEndConditions, - OverlapCondition overlapCondition, - TrivialChunkFilter trivialChunkFilter, - ChunkPostProcessor chunkPostProcessor) { - this.chunkEndConditions = Collections.unmodifiableList(chunkEndConditions); - this.overlapCondition = overlapCondition; - this.trivialChunkFilter = trivialChunkFilter; - this.chunkPostProcessor = chunkPostProcessor; - } - - /** - * Splits a document into chunks. - * - * @param document the document to split - * @return chunks - */ - public Flux splitDocument(Document document) { - return splitDocument(document, chunkEndConditions, overlapCondition, trivialChunkFilter, - chunkPostProcessor); - } - - /** - * Splits a document into chunks. - * - * @param document the document to split - * @param chunkEndConditions the conditions that determine the end of a chunk - * @param overlapCondition the condition that determines the overlap between chunks - * @param trivialChunkFilter the filter that determines if a chunk is trivial - * @param chunkPostProcessor the post processor to apply to the chunks - * @return a flux of chunks - */ - public static Flux splitDocument( - Document document, - List chunkEndConditions, - OverlapCondition overlapCondition, - TrivialChunkFilter trivialChunkFilter, - ChunkPostProcessor chunkPostProcessor) { - - return document - .getContent() - //TODO: Make the chunking work on true streaming data - .reduce("", (a, b) -> a + b) - .flatMapMany(doc -> { - List chunks = chunkDocument( - chunkEndConditions, - overlapCondition, - trivialChunkFilter, - chunkPostProcessor, - doc); - - return Flux.fromIterable(chunks); - }); - } - - private static List chunkDocument(List chunkEndConditions, - OverlapCondition overlapCondition, TrivialChunkFilter trivialChunkFilter, - ChunkPostProcessor chunkPostProcessor, String doc) { - List chunks = new ArrayList<>(); - - int previousChunkEndIndex = -1; - - while (doc != null && doc.length() > 0) { - - String finalDoc = doc; - - Optional index = chunkEndConditions - .stream() - .map(condition -> condition.getEndOfNextChunk(finalDoc)) - .filter(i -> i != -1) - .min(Integer::compareTo); - - if (index.isPresent()) { - String chunkText = doc.substring(0, index.get()); - - if (chunkText.length() <= previousChunkEndIndex) { - LOGGER.warn( - "This entier chunk consists of overlapped data, this will result in infinite loop. Skipping this chunk."); - - // previous chunk should already contain this text..skip it - doc = doc.substring(Math.min(previousChunkEndIndex, doc.length()), - doc.length()); - - previousChunkEndIndex = -1; - continue; - } - - int overlapIndex = overlapCondition.getOverlapIndex(chunkText); - previousChunkEndIndex = chunkText.length() - overlapIndex; - doc = doc.substring(Math.min(overlapIndex, doc.length()), doc.length()); - - chunks.add(new Chunk(chunkText)); - } else { - chunks.add(new Chunk(doc)); - break; - } - } - - chunks = mergeTrivialChunks(chunks, trivialChunkFilter); - chunks = tidyChunks(chunks, chunkPostProcessor); - return chunks; - } - - /** - * Tidies up the chunks by applying the post processor. - * - * @param chunks the list of chunks to tidy - * @param chunkPostProcessor the post processor to apply - * @return the list of tidied chunks - */ - private static List tidyChunks(List chunks, - ChunkPostProcessor chunkPostProcessor) { - return chunks - .stream() - .map(chunkPostProcessor::process) - .toList(); - } - - /** - * Merges chunks considered trivial into the previous chunk. - * - * @param chunks the list of chunks to merge - * @param trivialChunkFilter the filter to determine if a chunk is trivial - * @return the list of chunks with trivial chunks merged - */ - private static List mergeTrivialChunks(List chunks, - TrivialChunkFilter trivialChunkFilter) { - - List result = new ArrayList<>(); - Chunk current = null; - for (int i = 0; i < chunks.size(); i++) { - if (current == null) { - current = chunks.get(i); - } else { - current = new Chunk( - current.getContents() + chunks.get(i).getContents()); - } - - if (!trivialChunkFilter.isTrivialChunk(current.getContents())) { - result.add(current); - current = null; - } - } - - if (current != null) { - Chunk last = result.remove(result.size() - 1); - result.add(new Chunk(last.getContents() + current.getContents())); - } - - return result; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private List chunkEndConditions = new ArrayList<>(); - private OverlapCondition overlapCondition = new NoOverlapCondition(); - private TrivialChunkFilter trivialChunkFilter = new WhiteSpaceFilter(10); - private ChunkPostProcessor chunkPostProcessor; - - /** - * Splits the document into chunks based on the number of sentences. - * - * @param maxSentencesPerChunk the number of sentences per chunk - * @return the builder - */ - public Builder maxSentencesPerChunk(int maxSentencesPerChunk) { - return addChunkEndCondition( - new CountSplitCondition(maxSentencesPerChunk, new SentenceSplitter())); - } - - /** - * Splits the document into chunks based on the number of words. - * - * @param maxWordsPerChunk the number of words per chunk - * @return the builder - */ - public Builder maxWordsPerChunk(int maxWordsPerChunk) { - return addChunkEndCondition( - new CountSplitCondition(maxWordsPerChunk, new WordSplitter())); - } - - /** - * Splits the document into chunks based on the number of lines. - * - * @param maxLinesPerChunk the number of lines per chunk - * @return the builder - */ - public Builder maxLinesPerChunk(int maxLinesPerChunk) { - return addChunkEndCondition( - new CountSplitCondition(maxLinesPerChunk, new NewLineSplitter())); - } - - /** - * Splits the document into chunks based on the number of paragraphs. - *

- * NOTE: The ParagraphSplitter is not perfect, see {@link ParagraphSplitter} for more - * information. - * - * @param maxParagraphsPerChunk the number of paragraphs per chunk - * @return the builder - */ - public Builder maxParagraphsPerChunk(int maxParagraphsPerChunk) { - return addChunkEndCondition( - new CountSplitCondition(maxParagraphsPerChunk, new ParagraphSplitter())); - } - - /** - * Overlaps chunks by the given number of lines. - * - * @param overlap the number of characters to overlap - * @return the builder - */ - public Builder overlapNLines(int overlap) { - return setOverlapCondition(new CountOverlapCondition(overlap, new NewLineSplitter())); - } - - /** - * Overlaps chunks by the given number of sentences. - * - * @param overlap the number of sentences to overlap - * @return the builder - */ - public Builder overlapNSentences(int overlap) { - return setOverlapCondition(new CountOverlapCondition(overlap, new SentenceSplitter())); - } - - /** - * Overlaps chunks by the given number of words. - * - * @param overlap the number of words to overlap - * @return the builder - */ - public Builder overlapNWords(int overlap) { - return setOverlapCondition(new CountOverlapCondition(overlap, new WordSplitter())); - } - - /** - * Overlaps chunks by the given percentage. Percentage is calculated based on the number of - * characters in the chunk. Will split at the beginning of the word that gives the required - * percentage. - * - * @param overlap the percentage overlap - * @return the builder - */ - public Builder overlapNPercent(float overlap) { - return setOverlapCondition(new PercentageOverlapCondition(overlap, new WordSplitter())); - } - - /** - * Merges chunks that are less than the given character count. - * - * @param length the length of the chunk - * @return the builder - */ - public Builder mergeChunksLessThanCharCount(int length) { - return setTrivialSplitFilter(new WhiteSpaceFilter(length)); - } - - /** - * Trims whitespace from all chunks. - * - * @return the builder - */ - public Builder trimWhitespace() { - return setChunkPostProcessor(new RemoveWhitespace()); - } - - /** - * Adds a chunk post processor to the builder. This is used to process the chunk after it - * has been split. For example, to remove unwanted whitespace. - * - * @param chunkPostProcessor the post processor to add - * @return the builder - */ - public Builder setChunkPostProcessor(ChunkPostProcessor chunkPostProcessor) { - this.chunkPostProcessor = chunkPostProcessor; - return this; - } - - /** - * Adds a page end condition to the builder. These are applied as OR conditions, i.e the - * page will be the size of the SMALLEST condition. - * - * @param chunkEndCondition - * @return - */ - public Builder addChunkEndCondition(ChunkEndCondition chunkEndCondition) { - chunkEndConditions.add(chunkEndCondition); - return this; - } - - /** - * Adds an overlap condition to the builder. This condition is used to determine the overlap - * between chunks. - * - * @param overlapCondition - * @return the builder - */ - public Builder setOverlapCondition(OverlapCondition overlapCondition) { - this.overlapCondition = overlapCondition; - return this; - } - - /** - * Adds a trivial split filter to the builder. Pages that match this filter will be merged - * into the previous chunk. - * - * @param trivialChunkFilter - * @return the builder - */ - public Builder setTrivialSplitFilter(TrivialChunkFilter trivialChunkFilter) { - this.trivialChunkFilter = trivialChunkFilter; - return this; - } - - public Splitter build() { - if (chunkEndConditions.size() == 0) { - throw new SKException( - "At least one chunk end condition must be provided"); - } - return new Splitter( - chunkEndConditions, - overlapCondition, - trivialChunkFilter, - chunkPostProcessor); - } - - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TextSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TextSplitter.java deleted file mode 100644 index e579d3c78..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TextSplitter.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SplitPoint; -import java.util.List; - -/** - * Interface for splitting text into chunks. - */ -public interface TextSplitter { - - /** - * Get all the split points for the given document. - * - * @param doc the document to split - * @return the split points - */ - default List getSplitPoints(String doc) { - return getNSplitPoints(doc, Integer.MAX_VALUE); - } - - /** - * Get the first n split points for the given document. - * - * @param doc the document to split - * @param n the number of split points to get - * @return the split points - */ - List getNSplitPoints(String doc, int n); -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TrivialChunkFilter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TrivialChunkFilter.java deleted file mode 100644 index 206a6da0d..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/TrivialChunkFilter.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting; - -/** - * A filter that determines if a chunk is trivial and should be merged with the previous chunk. - */ -public interface TrivialChunkFilter { - - /** - * Returns true if the chunk is trivial and should be merged with the previous chunk. - * - * @param doc the chunk to be checked - * @return true if the chunk is trivial - */ - public boolean isTrivialChunk(String doc); - -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/document/TextDocument.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/document/TextDocument.java deleted file mode 100644 index 046d411dd..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/document/TextDocument.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.document; - -import com.microsoft.semantic.kernel.rag.splitting.Document; -import reactor.core.publisher.Flux; - -/** - * A document that contains a plain text string. - */ -public class TextDocument implements Document { - - private final String document; - - public TextDocument(String document) { - this.document = document; - } - - @Override - public Flux getContent() { - return Flux.just(document); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/CountOverlapCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/CountOverlapCondition.java deleted file mode 100644 index d3740653e..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/CountOverlapCondition.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.overlap; - -import com.microsoft.semantic.kernel.rag.splitting.OverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.TextSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SplitPoint; -import java.util.List; - -/** - * Overlap condition based on counting the number of "splits" i.e if splitting by words, would allow - * you to define an overlap as n words, or if by sentences, then n sentences. - */ -public class CountOverlapCondition implements OverlapCondition { - - // The number of splits to count to consider the condition met - private final int count; - - // The type of splitter to use to get the split points. - private final TextSplitter splitter; - - public CountOverlapCondition(int count, TextSplitter splitter) { - this.count = count; - this.splitter = splitter; - } - - @Override - public int getOverlapIndex(String chunk) { - List splitPoints = splitter.getSplitPoints(chunk); - - if (splitPoints.size() == 0) { - return 0; - } - - int i = Math.max(splitPoints.size() - count, 0); - i = Math.min(splitPoints.size() - 1, i); - - return splitPoints.get(i).getStart(); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/NoOverlapCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/NoOverlapCondition.java deleted file mode 100644 index 696a864cf..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/NoOverlapCondition.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.overlap; - -import com.microsoft.semantic.kernel.rag.splitting.OverlapCondition; - -/** - * An overlap condition that does not overlap. - */ -public class NoOverlapCondition implements OverlapCondition { - - public NoOverlapCondition() { - } - - public static OverlapCondition build() { - return new NoOverlapCondition(); - } - - @Override - public int getOverlapIndex(String chunk) { - return chunk.length(); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/PercentageOverlapCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/PercentageOverlapCondition.java deleted file mode 100644 index 797497081..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/overlap/PercentageOverlapCondition.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.overlap; - -import com.microsoft.semantic.kernel.rag.splitting.OverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.TextSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SplitPoint; -import java.util.List; -import org.slf4j.Logger; - -/** - * Overlap condition based on percentage of the characters in the chunk. It will return the full - * split that gives atleast the percentage of the characters in the chunk, i.e if you are splitting - * based on sentence it will return the full sentence. - */ -public class PercentageOverlapCondition implements OverlapCondition { - - private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger( - PercentageOverlapCondition.class); - - private final float percentage; - private final TextSplitter splitter; - - public PercentageOverlapCondition(float percentage, TextSplitter splitter) { - if (percentage < 0 || percentage > 100) { - LOGGER.warn("Percentage must be between 0 and 100, clamping value to this range 100"); - percentage = Math.min(100, Math.max(0, percentage)); - } - this.percentage = percentage; - this.splitter = splitter; - } - - @Override - public int getOverlapIndex(String chunk) { - List splitPoints = splitter.getSplitPoints(chunk); - - float index = chunk.length() * (100.0f - percentage) / 100.0f; - - for (SplitPoint splitPoint : splitPoints) { - if (splitPoint.getEnd() > index) { - return splitPoint.getStart(); - } - } - - return 0; - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/NoOpPostProcessor.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/NoOpPostProcessor.java deleted file mode 100644 index c1697e1a4..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/NoOpPostProcessor.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.postprocessors; - -import com.microsoft.semantic.kernel.rag.splitting.Chunk; -import com.microsoft.semantic.kernel.rag.splitting.ChunkPostProcessor; - -/** - * A post processor that does nothing. - */ -public class NoOpPostProcessor implements ChunkPostProcessor { - - public NoOpPostProcessor() { - } - - @Override - public Chunk process(Chunk chunk) { - return chunk; - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/RemoveWhitespace.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/RemoveWhitespace.java deleted file mode 100644 index 497fa664d..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/postprocessors/RemoveWhitespace.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.postprocessors; - -import com.microsoft.semantic.kernel.rag.splitting.Chunk; -import com.microsoft.semantic.kernel.rag.splitting.ChunkPostProcessor; - -/** - * A post processor that removes leading and trailing whitespace from a chunk. - */ -public class RemoveWhitespace implements ChunkPostProcessor { - - @Override - public Chunk process(Chunk chunk) { - return new Chunk(chunk.getContents() - .replaceAll("^\\s+", "") - .replaceAll("^[\n\r]+", "") - .replaceAll("\\s+$", "") - .replaceAll("[\n\r]+$", "")); - } - -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/CountSplitCondition.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/CountSplitCondition.java deleted file mode 100644 index 4734cadc0..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/CountSplitCondition.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import com.microsoft.semantic.kernel.rag.splitting.ChunkEndCondition; -import com.microsoft.semantic.kernel.rag.splitting.TextSplitter; -import java.util.List; - -/** - * Overlap condition based on counting the number of "splits" i.e if splitting by words, would allow - * you to define a chunk as n words, or if by sentences, then n sentences. - */ -public class CountSplitCondition implements ChunkEndCondition { - - private final int count; - private final TextSplitter splitter; - - public CountSplitCondition(int count, TextSplitter splitter) { - this.count = count; - this.splitter = splitter; - } - - @Override - public int getEndOfNextChunk(String doc) { - List splitPoints = splitter.getNSplitPoints(doc, count) - .stream() - .filter(it -> it != null) - .filter(it -> it.getEnd() != 0) - .filter(it -> it.getEnd() != it.getStart()) - .filter(it -> it.getStart() != doc.length()) - .toList(); - - if (splitPoints.size() < count) { - return splitPoints.get(splitPoints.size() - 1).getEnd(); - } - - return splitPoints.get(count - 1).getEnd(); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/NewLineSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/NewLineSplitter.java deleted file mode 100644 index f4f1a3d94..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/NewLineSplitter.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import java.util.regex.Pattern; - -/** - * A splitter that splits text based on new lines. - */ -public class NewLineSplitter extends RegexSplitter { - - private static final Pattern NEW_LINE_SPLIT_REGEX = Pattern - .compile("[(\\r\\n)\\n\\r]+", Pattern.MULTILINE); - - public NewLineSplitter() { - super(NEW_LINE_SPLIT_REGEX); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/ParagraphSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/ParagraphSplitter.java deleted file mode 100644 index 958079f8c..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/ParagraphSplitter.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import java.util.regex.Pattern; - -/** - * A splitter that splits text into paragraphs. - *

- * This is a very simple and inaccurate splitter that splits text into paragraphs based on either: - *

- *

    - *
  • Two or more consecutive newlines.
  • - *
  • A line ending in a end sentence character (i.e a period)
  • - *
- */ -public class ParagraphSplitter extends RegexSplitter { - - private static final Pattern PARAGRAPH_SPLIT_REGEX = Pattern - .compile("[(\\r\\n)\\n\\r]{2,}|([\\.\\.!\\?。]+\\s*[(\\r\\n)\\n\\r])", Pattern.MULTILINE); - - public ParagraphSplitter() { - super(PARAGRAPH_SPLIT_REGEX); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/RegexSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/RegexSplitter.java deleted file mode 100644 index 5828e4a44..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/RegexSplitter.java +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import com.microsoft.semantic.kernel.rag.splitting.TextSplitter; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * A text splitter that uses a regex to find the deliminators - */ -public abstract class RegexSplitter implements TextSplitter { - - public static final int DEFAULT_TRIVIAL_SPLIT_LENGTH = 10; - - private final Pattern pattern; - /** - * Splits below this length are considered trivial and will be merged - */ - private final int trivialSplitLength; - - /** - * Splitter that uses the given regex pattern to split the text - * - * @param pattern the regex pattern to split the text - */ - public RegexSplitter(Pattern pattern) { - this(pattern, DEFAULT_TRIVIAL_SPLIT_LENGTH); - } - - /** - * Splitter that uses the given regex pattern to split the text - * - * @param pattern the regex pattern to split the text - * @param trivialSplitLength the length of a split below which it will be considered trivial and - * will be merged - */ - public RegexSplitter(Pattern pattern, int trivialSplitLength) { - this.pattern = pattern; - this.trivialSplitLength = trivialSplitLength; - } - - @Override - public List getNSplitPoints(String doc, int n) { - Matcher matcher = pattern.matcher(doc); - - List points = matcher.results() - .collect(Collectors.toList()); - - List result = new ArrayList<>(); - - int previousEnd = 0; - for (MatchResult point : points) { - if (isTrivialSplit( - /* start= */ previousEnd, - /* end= */ point.start(), - doc, - trivialSplitLength)) { - continue; - } - result.add(new SplitPoint(previousEnd, point.end())); - previousEnd = point.end(); - if (result.size() >= n) { - break; - } - } - - if (result.size() < n && !isTrivialSplit(previousEnd, doc.length(), doc, 1)) { - result.add(new SplitPoint(previousEnd, doc.length())); - } - - if (result.isEmpty()) { - return List.of(new SplitPoint(0, doc.length())); - } - - return result; - } - - private boolean isTrivialSplit(int start, int end, String doc, int trivialSplitLength) { - String split = doc.substring(start, end); - - // Remove all split characters and whitespace - split = pattern.matcher(split).replaceAll(""); - split = split.replaceAll("\\s+", ""); - - return split.length() <= trivialSplitLength; - - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SentenceSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SentenceSplitter.java deleted file mode 100644 index bfe5e7e53..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SentenceSplitter.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import java.util.regex.Pattern; - -/** - * A splitter that splits text into sentences. - */ -public class SentenceSplitter extends RegexSplitter { - - private static final Pattern SENTENCE_SPLIT_REGEX = Pattern - .compile("[\\.\\.!\\?。]+", Pattern.MULTILINE); - - public SentenceSplitter() { - super(SENTENCE_SPLIT_REGEX); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SplitPoint.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SplitPoint.java deleted file mode 100644 index 8f621adb7..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/SplitPoint.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -/** - * A class that represents the start and end points of a split. I.e if splitting by word, these - * would be the indices of the first and last char in the word within the chunk. - */ -public class SplitPoint { - - private final int start; - private final int end; - - public SplitPoint(int start, int end) { - this.start = start; - this.end = end; - } - - /** - * The index of the first character in the split. - * - * @return the index of the first character in the split - */ - public int getStart() { - return start; - } - - /** - * The index of the last character in the split. - * - * @return the index of the last character in the split - */ - public int getEnd() { - return end; - } -} \ No newline at end of file diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WhiteSpaceFilter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WhiteSpaceFilter.java deleted file mode 100644 index 8dabbf40a..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WhiteSpaceFilter.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import com.microsoft.semantic.kernel.rag.splitting.TrivialChunkFilter; - -/** - * A filter that merges chunks that have less than N non-whitespace characters. - */ -public class WhiteSpaceFilter implements TrivialChunkFilter { - - private final int trivialCharacterCount; - - public WhiteSpaceFilter(int trivialCharacterCount) { - this.trivialCharacterCount = trivialCharacterCount; - } - - @Override - public boolean isTrivialChunk(String doc) { - return doc.replaceAll("\\s+", "").length() < trivialCharacterCount; - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WordSplitter.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WordSplitter.java deleted file mode 100644 index 8a0e6852f..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/main/java/com/microsoft/semantic/kernel/rag/splitting/splitconditions/WordSplitter.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantic.kernel.rag.splitting.splitconditions; - -import java.util.regex.Pattern; - -/** - * A splitter that splits text into words. - */ -public class WordSplitter extends RegexSplitter { - - private static final Pattern WORD_SPLIT_REGEX = Pattern - .compile("[,、;: ()\\[\\]{}\t\n]+", Pattern.MULTILINE); - - public WordSplitter() { - super(WORD_SPLIT_REGEX, 1); - } -} diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/test/java/DocumentSplitTest.java b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/test/java/DocumentSplitTest.java deleted file mode 100644 index edd054919..000000000 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/src/test/java/DocumentSplitTest.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -import com.microsoft.semantic.kernel.rag.splitting.Chunk; -import com.microsoft.semantic.kernel.rag.splitting.Splitter; -import com.microsoft.semantic.kernel.rag.splitting.document.TextDocument; -import com.microsoft.semantic.kernel.rag.splitting.overlap.CountOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.overlap.PercentageOverlapCondition; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.CountSplitCondition; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.NewLineSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.ParagraphSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.SentenceSplitter; -import com.microsoft.semantic.kernel.rag.splitting.splitconditions.WordSplitter; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class DocumentSplitTest { - - private final String NUMBERS = """ - 01 02 03 04 05 06 07 08 09 10. - 11 12 13 14 15 16 17 18 19 20. - 21 22 23 24 25 26 27 28 29 30. - 31 32 33 34 35 36 37 38 39 40. - 41 42 43 44 45 46 47 48 49 50. - 51 52 53 54 55 56 57 58 59 60. - 61 62 63 64 65 66 67 68 69 70. - 71 72 73 74 75 76 77 78 79 80. - 81 82 83 84 85 86 87 88 89 90. - 91 92 93 94 95 96 97 98 99 100. - """.stripIndent(); - - private final String PARAGRAPHS = """ - 01 02 03 04 05 06 07 08 09 10. 11 12 13 14 15 - 16 17 18 19 20. 21 22 23 24 - 25 26 27 28 29 30. - - 31 32 33 34 35 36 37 38 39 40. 41 42 43 44 - 45 46 47 48 49 50. - - 51 52 53 54 55 56 57 58 59 60. 61 - 62 63 64 65 66 67 68 69 70. 71 72 73 - 74 75 76 77 78 79 80. - - - 81 82 83 84 85 86 87 88 89 90. - - - 91 92 93 94 95 96 97 98 99 100. - """.stripIndent(); - - @Test - public void testWordSplit() { - List chunks = Splitter.builder() - .addChunkEndCondition(new CountSplitCondition(9, new WordSplitter())) - .setOverlapCondition(new PercentageOverlapCondition(20.0f, new WordSplitter())) - .trimWhitespace() - .build() - .splitDocument(new TextDocument(NUMBERS)) - .collectList() - .block(); - - Assertions.assertEquals(14, chunks.size()); - - Assertions.assertEquals(""" - 01 02 03 04 05 06 07 08 09""" - .stripIndent(), chunks.get(0).getContents()); - - Assertions.assertEquals(""" - 08 09 10. - 11 12 13 14 15 16""" - .stripIndent(), chunks.get(1).getContents()); - - Assertions.assertEquals(""" - 92 93 94 95 96 97 98 99 100.""" - .stripIndent(), chunks.get(13).getContents()); - } - - @Test - public void testSentenceSplit() { - List chunks = Splitter.builder() - .addChunkEndCondition(new CountSplitCondition(4, new SentenceSplitter())) - .setOverlapCondition(new CountOverlapCondition(2, new SentenceSplitter())) - .trimWhitespace() - .build() - .splitDocument(new TextDocument(NUMBERS)) - .collectList() - .block(); - - Assertions.assertEquals(4, chunks.size()); - - Assertions.assertEquals(""" - 01 02 03 04 05 06 07 08 09 10. - 11 12 13 14 15 16 17 18 19 20. - 21 22 23 24 25 26 27 28 29 30. - 31 32 33 34 35 36 37 38 39 40.""" - .stripIndent(), chunks.get(0).getContents()); - Assertions.assertEquals(""" - 21 22 23 24 25 26 27 28 29 30. - 31 32 33 34 35 36 37 38 39 40. - 41 42 43 44 45 46 47 48 49 50. - 51 52 53 54 55 56 57 58 59 60.""" - .stripIndent(), chunks.get(1).getContents()); - Assertions.assertEquals(""" - 61 62 63 64 65 66 67 68 69 70. - 71 72 73 74 75 76 77 78 79 80. - 81 82 83 84 85 86 87 88 89 90. - 91 92 93 94 95 96 97 98 99 100.""" - .stripIndent(), chunks.get(3).getContents()); - } - - @Test - public void testParagraphSplitter() { - - List chunks = Splitter.builder() - .addChunkEndCondition(new CountSplitCondition(2, new ParagraphSplitter())) - .setOverlapCondition(new CountOverlapCondition(2, new WordSplitter())) - .trimWhitespace() - .build() - .splitDocument(new TextDocument(PARAGRAPHS)) - .collectList() - .block(); - - Assertions.assertEquals( - """ - 01 02 03 04 05 06 07 08 09 10. 11 12 13 14 15 - 16 17 18 19 20. 21 22 23 24 - 25 26 27 28 29 30. - - 31 32 33 34 35 36 37 38 39 40. 41 42 43 44 - 45 46 47 48 49 50.""".stripIndent(), - chunks.get(0).getContents()); - - Assertions.assertEquals( - """ - 89 90. - - - 91 92 93 94 95 96 97 98 99 100.""".stripIndent(), - chunks.get(2).getContents()); - } - - @Test - public void testNewLineSplitter() { - - List chunks = Splitter.builder() - .addChunkEndCondition(new CountSplitCondition(2, new NewLineSplitter())) - .trimWhitespace() - .build() - .splitDocument(new TextDocument(PARAGRAPHS)) - .collectList() - .block(); - - Assertions.assertEquals( - """ - 01 02 03 04 05 06 07 08 09 10. 11 12 13 14 15 - 16 17 18 19 20. 21 22 23 24""".stripIndent(), - chunks.get(0).getContents()); - Assertions.assertEquals( - """ - 25 26 27 28 29 30. - - 31 32 33 34 35 36 37 38 39 40. 41 42 43 44""".stripIndent(), - chunks.get(1).getContents()); - - Assertions.assertEquals( - """ - 81 82 83 84 85 86 87 88 89 90. - - - 91 92 93 94 95 96 97 98 99 100.""".stripIndent(), - chunks.get(4).getContents()); - } -} diff --git a/semantickernel-api-ai-services/pom.xml b/semantickernel-api-ai-services/pom.xml deleted file mode 100644 index 6187b56b4..000000000 --- a/semantickernel-api-ai-services/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - Semantic Kernel AI Services API - Defines the public interface for the Semantic Kernel Services - - - - com.google.code.findbugs - jsr305 - provided - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/semantickernel-api-ai-services/src/main/java/com/microsoft/semantickernel/services/AIService.java b/semantickernel-api-ai-services/src/main/java/com/microsoft/semantickernel/services/AIService.java deleted file mode 100644 index ce7e36435..000000000 --- a/semantickernel-api-ai-services/src/main/java/com/microsoft/semantickernel/services/AIService.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import javax.annotation.Nullable; - -/** - * Marker interface for AI services. {@code AIService}s are registered with the {@code Kernel} and - * are used to provide access to AI services. - */ -public interface AIService { - - /** - * Gets the model identifier. - * - * @return The model identifier if it was specified in the service's attributes; otherwise, - * {@code null}. - */ - @Nullable - String getModelId(); - - /** - * Gets the service identifier. - * - * @return The service identifier. - */ - @Nullable - String getServiceId(); -} diff --git a/semantickernel-api-builders/pom.xml b/semantickernel-api-builders/pom.xml deleted file mode 100644 index be51b46f7..000000000 --- a/semantickernel-api-builders/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - - - com.microsoft.semantic-kernel - semantickernel-api-builders - Semantic Kernel Builders API - Defines the public interface for the Semantic Kernel Builders - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/semantickernel-api-builders/src/main/java/com/microsoft/semantickernel/builders/SemanticKernelBuilder.java b/semantickernel-api-builders/src/main/java/com/microsoft/semantickernel/builders/SemanticKernelBuilder.java deleted file mode 100644 index 7b50fa624..000000000 --- a/semantickernel-api-builders/src/main/java/com/microsoft/semantickernel/builders/SemanticKernelBuilder.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.builders; - -/** - * Interface for all builders. - * - * @param the type to build. - */ -public interface SemanticKernelBuilder { - - /** - * Build the object. - * - * @return a constructed object. - */ - T build(); -} diff --git a/semantickernel-api-data/pom.xml b/semantickernel-api-data/pom.xml deleted file mode 100644 index 13bd19931..000000000 --- a/semantickernel-api-data/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-api-data - Semantic Kernel Data API - Defines the public interface for the Semantic Kernel Data - - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - provided - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - provided - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - provided - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - io.projectreactor - reactor-core - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - \ No newline at end of file diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearch.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearch.java deleted file mode 100644 index 7ae381115..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearch.java +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import com.microsoft.semantickernel.data.textsearch.DefaultTextSearchResultMapper; -import com.microsoft.semantickernel.data.textsearch.DefaultTextSearchStringMapper; -import com.microsoft.semantickernel.data.textsearch.KernelSearchResults; -import com.microsoft.semantickernel.data.textsearch.TextSearch; -import com.microsoft.semantickernel.data.textsearch.TextSearchOptions; -import com.microsoft.semantickernel.data.textsearch.TextSearchResult; -import com.microsoft.semantickernel.data.textsearch.TextSearchResultMapper; -import com.microsoft.semantickernel.data.textsearch.TextSearchStringMapper; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService; -import reactor.core.publisher.Mono; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.stream.Collectors; - -/** - * A text search implementation that uses a vector record collection to perform the search. - * - * @param The record type. - */ -public class VectorStoreTextSearch implements TextSearch { - - private final VectorizedSearch vectorizedSearch; - private final TextEmbeddingGenerationService textEmbeddingGenerationService; - private final TextSearchStringMapper stringMapper; - private final TextSearchResultMapper resultMapper; - private final VectorStoreTextSearchOptions options; - - /** - * Create a new instance of VectorStoreTextSearch with {@link VectorizedSearch} to perform vectorized search and - * {@link TextEmbeddingGenerationService} to generate text embeddings. - * - * @param vectorizedSearch The vectorized search. Usually a vector record collection. - * @param textEmbeddingGenerationService The text embedding generation service. - * @param stringMapper The string mapper. - * @param resultMapper The result mapper. - * @param options The options. - */ - public VectorStoreTextSearch( - @Nonnull VectorizedSearch vectorizedSearch, - @Nonnull TextEmbeddingGenerationService textEmbeddingGenerationService, - @Nullable TextSearchStringMapper stringMapper, - @Nullable TextSearchResultMapper resultMapper, - @Nullable VectorStoreTextSearchOptions options) { - this.vectorizedSearch = vectorizedSearch; - this.textEmbeddingGenerationService = textEmbeddingGenerationService; - this.stringMapper = stringMapper == null ? new DefaultTextSearchStringMapper() - : stringMapper; - this.resultMapper = resultMapper == null ? new DefaultTextSearchResultMapper() - : resultMapper; - this.options = options == null ? new VectorStoreTextSearchOptions() : options; - } - - private Mono> executeSearchAsync(String query, - TextSearchOptions options) { - if (options == null) { - options = TextSearchOptions.createDefault(); - } - - VectorSearchOptions vectorSearchOptions = VectorSearchOptions.builder() - .withVectorSearchFilter(options.getFilter() != null - ? new VectorSearchFilter(options.getFilter().getFilterClauses()) - : null) - .withTop(options.getTop()) - .withSkip(options.getSkip()) - .withIncludeTotalCount(options.isIncludeTotalCount()) - .build(); - - return textEmbeddingGenerationService.generateEmbeddingAsync(query) - .flatMap(embedding -> vectorizedSearch.searchAsync(embedding.getVector(), - vectorSearchOptions)); - } - - /** - * Perform a search for content related to the specified query and return String values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - @Override - public Mono> searchAsync(String query, TextSearchOptions options) { - return executeSearchAsync(query, options) - .map(results -> new KernelSearchResults<>( - results.getResults().stream() - .map(r -> stringMapper.fromResultToString(r.getRecord())) - .collect(Collectors.toList()), - results.getTotalCount(), - results.getMetadata())); - } - - /** - * Perform a search for content related to the specified query and return TextSearchResult values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - @Override - public Mono> getTextSearchResultsAsync(String query, - TextSearchOptions options) { - return executeSearchAsync(query, options) - .map(results -> new KernelSearchResults<>( - results.getResults().stream() - .map(r -> resultMapper.fromResultToTextSearchResult(r.getRecord())) - .collect(Collectors.toList()), - results.getTotalCount(), - results.getMetadata())); - } - - /** - * Perform a search for content related to the specified query and return Object values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - @Override - public Mono> getSearchResultsAsync(String query, - TextSearchOptions options) { - return executeSearchAsync(query, options) - .map(results -> new KernelSearchResults<>( - results.getResults().stream() - .map(r -> resultMapper.fromResultToTextSearchResult(r.getRecord())) - .collect(Collectors.toList()), - results.getTotalCount(), - results.getMetadata())); - } - - /** - * Create a new instance of {@link Builder}. - * - * @param The record type. - * @return The builder. - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * A builder for the {@link VectorStoreTextSearch} class. - * - * @param The record type. - */ - public static class Builder { - @Nullable - private VectorizedSearch vectorizedSearch; - @Nullable - private TextEmbeddingGenerationService textEmbeddingGenerationService; - @Nullable - private TextSearchStringMapper stringMapper; - @Nullable - private TextSearchResultMapper resultMapper; - @Nullable - private VectorStoreTextSearchOptions options; - - /** - * Sets the vectorized search. - * - * @param vectorizedSearch The vectorized search. - * @return The builder. - */ - public Builder withVectorizedSearch(VectorizedSearch vectorizedSearch) { - this.vectorizedSearch = vectorizedSearch; - return this; - } - - /** - * Sets the text embedding generation service. - * - * @param textEmbeddingGenerationService The text embedding generation service. - * @return The builder. - */ - public Builder withTextEmbeddingGenerationService( - TextEmbeddingGenerationService textEmbeddingGenerationService) { - this.textEmbeddingGenerationService = textEmbeddingGenerationService; - return this; - } - - /** - * Sets the string mapper. - * - * @param stringMapper The string mapper. - * @return The builder. - */ - public Builder withStringMapper(TextSearchStringMapper stringMapper) { - this.stringMapper = stringMapper; - return this; - } - - /** - * Sets the result mapper. - * - * @param resultMapper The result mapper. - * @return The builder. - */ - public Builder withResultMapper(TextSearchResultMapper resultMapper) { - this.resultMapper = resultMapper; - return this; - } - - /** - * Sets the options. - * - * @param options The options. - * @return The builder. - */ - public Builder withOptions(VectorStoreTextSearchOptions options) { - this.options = options; - return this; - } - - /** - * Builds the {@link VectorStoreTextSearch} instance. - * - * @return The {@link VectorStoreTextSearch} instance. - */ - public VectorStoreTextSearch build() { - if (vectorizedSearch == null) { - throw new SKException("Vectorized search is required"); - } - if (textEmbeddingGenerationService == null) { - throw new SKException("Text embedding generation service is required"); - } - - return new VectorStoreTextSearch<>(vectorizedSearch, textEmbeddingGenerationService, - stringMapper, resultMapper, options); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearchOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearchOptions.java deleted file mode 100644 index 80a468ce5..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VectorStoreTextSearchOptions.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -/** - * Options for vector store text search. - */ -public class VectorStoreTextSearchOptions { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStore.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStore.java deleted file mode 100644 index dbb56da41..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStore.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nonnull; - -import com.microsoft.semantickernel.data.vectorstorage.VectorStore; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.exceptions.SKException; -import reactor.core.publisher.Mono; - -/** - * Represents a volatile vector store. - * A volatile vector store is an in-memory vector store - * that does not persist data. - */ -public class VolatileVectorStore implements VectorStore { - - private final Map> collections; - - /** - * Creates a new instance of the volatile vector store. - */ - public VolatileVectorStore() { - this.collections = new ConcurrentHashMap<>(); - } - - /** - * Gets a collection from the vector store. - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - * @return The collection. - */ - @Override - public VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull VectorStoreRecordCollectionOptions options) { - if (options.getKeyClass() != String.class) { - throw new SKException("Volatile only supports string keys"); - } - if (options.getRecordClass() == null) { - throw new SKException("Record class is required"); - } - - return (VectorStoreRecordCollection) new VolatileVectorStoreRecordCollection<>( - collectionName, - collections, - (VolatileVectorStoreRecordCollectionOptions) options); - } - - /** - * Gets the names of all collections in the vector store. - * - * @return A list of collection names. - */ - @Override - public Mono> getCollectionNamesAsync() { - return Mono.just(new ArrayList<>(collections.keySet())); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreCollectionSearchMapping.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreCollectionSearchMapping.java deleted file mode 100644 index 3a5eab6a4..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreCollectionSearchMapping.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.filter.FilterClause; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordField; -import com.microsoft.semantickernel.exceptions.SKException; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * Provides methods to filter records based on a {@link VectorSearchFilter}. - */ -public class VolatileVectorStoreCollectionSearchMapping { - - /** - * Filters the records based on the given {@link VectorSearchFilter}. - * - * @param records The records to filter. - * @param filter The filter to apply. - * @param recordDefinition The record definition. - * @param objectMapper The object mapper. - * @param The record type. - * @return The filtered records. - */ - public static List filterRecords(List records, - VectorSearchFilter filter, - VectorStoreRecordDefinition recordDefinition, ObjectMapper objectMapper) { - if (filter == null || filter.getFilterClauses().isEmpty()) { - return records; - } - - return records.stream().filter( - record -> { - JsonNode recordNode = objectMapper.valueToTree(record); - - for (FilterClause filterClause : filter.getFilterClauses()) { - if (filterClause instanceof EqualToFilterClause) { - EqualToFilterClause equalToFilterClause = (EqualToFilterClause) filterClause; - VectorStoreRecordField field = recordDefinition - .getField(equalToFilterClause.getFieldName()); - - Object value = objectMapper.convertValue( - recordNode.get(field.getEffectiveStorageName()), field.getFieldType()); - if (!equalToFilterClause.getValue().equals(value)) { - return false; - } - } else { - throw new SKException(String.format("Unsupported filter clause type '%s'.", - filterClause.getClass().getSimpleName())); - } - } - return true; - }).collect(Collectors.toList()); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollection.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollection.java deleted file mode 100644 index a8ef8a654..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollection.java +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.microsoft.semantickernel.data.vectorsearch.VectorOperations; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -/** - * Represents a volatile vector store record collection. - * - * @param The type of record in the collection. - */ -public class VolatileVectorStoreRecordCollection implements - VectorStoreRecordCollection { - - private static final HashSet> supportedKeyTypes = new HashSet<>( - Collections.singletonList(String.class)); - private Map> collections; - private final String collectionName; - private final VolatileVectorStoreRecordCollectionOptions options; - private final VectorStoreRecordDefinition recordDefinition; - private final ObjectMapper objectMapper; - - /** - * Creates a new instance of the volatile vector store record collection. - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - */ - public VolatileVectorStoreRecordCollection(String collectionName, - VolatileVectorStoreRecordCollectionOptions options) { - this.collectionName = collectionName; - this.options = options; - this.collections = new ConcurrentHashMap<>(); - - if (options.getRecordDefinition() != null) { - this.recordDefinition = options.getRecordDefinition(); - } else { - this.recordDefinition = VectorStoreRecordDefinition - .fromRecordClass(this.options.getRecordClass()); - } - - if (options.getObjectMapper() == null) { - this.objectMapper = new ObjectMapper(); - } else { - this.objectMapper = options.getObjectMapper(); - } - - // Validate the key type - VectorStoreRecordDefinition.validateSupportedTypes( - Collections.singletonList(recordDefinition.getKeyField()), - supportedKeyTypes); - } - - VolatileVectorStoreRecordCollection(String collectionName, - Map> collections, - VolatileVectorStoreRecordCollectionOptions options) { - this(collectionName, options); - this.collections = collections; - } - - /** - * Gets the name of the collection. - * - * @return The name of the collection. - */ - @Override - public String getCollectionName() { - return collectionName; - } - - /** - * Checks if the collection exists in the store. - * - * @return A Mono emitting a boolean indicating if the collection exists. - */ - @Override - public Mono collectionExistsAsync() { - return Mono.fromCallable(() -> collections.containsKey(collectionName)); - } - - /** - * Creates the collection in the store. - * - * @return A Mono representing the completion of the creation operation. - */ - @Override - public Mono> createCollectionAsync() { - return Mono.fromRunnable(() -> collections.put(collectionName, new ConcurrentHashMap<>())) - .then(Mono.just(this)); - } - - /** - * Creates the collection in the store if it does not exist. - * - * @return A Mono representing the completion of the creation operation. - */ - @Override - public Mono> createCollectionIfNotExistsAsync() { - return Mono - .fromRunnable(() -> collections.putIfAbsent(collectionName, new ConcurrentHashMap<>())) - .then(Mono.just(this)); - } - - /** - * Deletes the collection from the store. - * - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteCollectionAsync() { - return Mono.fromRunnable(() -> collections.remove(collectionName)); - } - - /** - * Gets a record from the store. - * - * @param key The key of the record to get. - * @param options The options for getting the record. - * @return A Mono emitting the record. - */ - @Override - public Mono getAsync(String key, GetRecordOptions options) { - return Mono.fromCallable(() -> getCollection().get(key)); - } - - /** - * Gets a batch of records from the store. - * - * @param keys The keys of the records to get. - * @param options The options for getting the records. - * @return A Mono emitting a list of records. - */ - @Override - public Mono> getBatchAsync(List keys, GetRecordOptions options) { - return Mono.fromCallable(() -> { - Map collection = getCollection(); - return keys.stream().map(collection::get).collect(Collectors.toList()); - }); - } - - /** - * Inserts or updates a record in the store. - * - * @param data The record to upsert. - * @param options The options for upserting the record. - * @return A Mono emitting the key of the upserted record. - */ - @Override - public Mono upsertAsync(Record data, UpsertRecordOptions options) { - return Mono.fromCallable(() -> { - try { - ObjectNode objectNode = objectMapper.valueToTree(data); - String key = objectNode - .get(recordDefinition.getKeyField().getEffectiveStorageName()).asText(); - - getCollection().put(key, data); - return key; - } catch (Exception e) { - throw new SKException( - "Failure to serialize object. Ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }); - } - - /** - * Inserts or updates a batch of records in the store. - * - * @param data The records to upsert. - * @param options The options for upserting the records. - * @return A Mono emitting a list of keys of the upserted records. - */ - @Override - public Mono> upsertBatchAsync(List data, UpsertRecordOptions options) { - return Mono.fromCallable(() -> { - Map collection = getCollection(); - return data.stream().map(record -> { - try { - ObjectNode objectNode = objectMapper.valueToTree(record); - String key = objectNode - .get(recordDefinition.getKeyField().getEffectiveStorageName()).asText(); - - collection.put(key, record); - return key; - } catch (Exception e) { - throw new SKException( - "Failure to serialize object. Ensure your model object can be serialized by Jackson, i.e the class is visible, has getters, constructor, annotations etc.", - e); - } - }).collect(Collectors.toList()); - }); - } - - /** - * Deletes a record from the store. - * - * @param key The key of the record to delete. - * @param options The options for deleting the record. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteAsync(String key, DeleteRecordOptions options) { - return Mono.fromRunnable(() -> getCollection().remove(key)); - } - - /** - * Deletes a batch of records from the store. - * - * @param strings The keys of the records to delete. - * @param options The options for deleting the records. - * @return A Mono representing the completion of the deletion operation. - */ - @Override - public Mono deleteBatchAsync(List strings, DeleteRecordOptions options) { - return Mono.fromRunnable(() -> { - Map collection = getCollection(); - strings.forEach(collection::remove); - }); - } - - private Map getCollection() { - if (!collections.containsKey(collectionName)) { - throw new IllegalStateException( - String.format("Collection %s does not exist.", collectionName)); - } - return (Map) collections.get(collectionName); - } - - private List arrayNodeToFloatList(ArrayNode arrayNode) { - return Stream.iterate(0, i -> i + 1) - .limit(arrayNode.size()) - .map(i -> arrayNode.get(i).floatValue()) - .collect(Collectors.toList()); - } - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param options The options to use for the search. - * @return A list of search results. - */ - @Override - public Mono> searchAsync(List vector, - final VectorSearchOptions options) { - if (recordDefinition.getVectorFields().isEmpty()) { - throw new SKException("No vector fields defined. Cannot perform vector search"); - } - - return Mono.fromCallable(() -> { - VectorStoreRecordVectorField firstVectorField = recordDefinition.getVectorFields() - .get(0); - VectorSearchOptions effectiveOptions = options == null - ? VectorSearchOptions.createDefault(firstVectorField.getName()) - : options; - - VectorStoreRecordVectorField vectorField = effectiveOptions.getVectorFieldName() == null - ? firstVectorField - : (VectorStoreRecordVectorField) recordDefinition - .getField(effectiveOptions.getVectorFieldName()); - - DistanceFunction distanceFunction = vectorField - .getDistanceFunction() == DistanceFunction.UNDEFINED - ? DistanceFunction.EUCLIDEAN_DISTANCE - : vectorField.getDistanceFunction(); - - List records = VolatileVectorStoreCollectionSearchMapping.filterRecords( - new ArrayList<>(getCollection().values()), effectiveOptions.getVectorSearchFilter(), - recordDefinition, objectMapper); - - return new VectorSearchResults<>( - VectorOperations.exactSimilaritySearch(records, vector, vectorField, - distanceFunction, effectiveOptions)); - }).subscribeOn(Schedulers.boundedElastic()); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionOptions.java deleted file mode 100644 index 0b5779df0..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollectionOptions; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents the options for a volatile vector store record collection. - * - * @param the record type - */ -public class VolatileVectorStoreRecordCollectionOptions - implements VectorStoreRecordCollectionOptions { - private final Class recordClass; - @Nullable - private final VectorStoreRecordDefinition recordDefinition; - @Nullable - private final ObjectMapper objectMapper; - - /** - * Creates a new instance of the Volatile vector store record collection options. - * - * @param recordClass The record class. - * @param recordDefinition The record definition. - * @param objectMapper An instanc of Jackson ObjectMapper. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // ObjectMapper only has package visibility - public VolatileVectorStoreRecordCollectionOptions(@Nonnull Class recordClass, - @Nullable VectorStoreRecordDefinition recordDefinition, ObjectMapper objectMapper) { - this.recordClass = recordClass; - this.recordDefinition = recordDefinition; - this.objectMapper = objectMapper; - } - - /** - * Creates a new builder. - * - * @param the record type - * @return the builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Gets the key class. - * - * @return the key class - */ - @Override - public Class getKeyClass() { - return String.class; - } - - /** - * Gets the record class. - * - * @return the record class - */ - public Class getRecordClass() { - return recordClass; - } - - /** - * Gets the object mapper. - * - * @return the object mapper - */ - ObjectMapper getObjectMapper() { - return objectMapper; - } - - /** - * Gets the record definition. - * - * @return the record definition - */ - public VectorStoreRecordDefinition getRecordDefinition() { - return recordDefinition; - } - - /** - * Builder for Volatile vector store record collection options. - * - * @param the record type - */ - public static class Builder { - @Nullable - private Class recordClass; - @Nullable - private VectorStoreRecordDefinition recordDefinition; - @Nullable - private ObjectMapper objectMapper; - - /** - * Sets the record class. - * - * @param recordClass the record class - * @return the builder - */ - public Builder withRecordClass(Class recordClass) { - this.recordClass = recordClass; - return this; - } - - /** - * Sets the record definition. - * - * @param recordDefinition the record definition - * @return the builder - */ - public Builder withRecordDefinition(VectorStoreRecordDefinition recordDefinition) { - this.recordDefinition = recordDefinition; - return this; - } - - /** - * Sets the object mapper. - * - * @param objectMapper the object mapper - * @return the builder - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - /** - * Builds the options. - * - * @return the options - */ - public VolatileVectorStoreRecordCollectionOptions build() { - if (recordClass == null) { - throw new IllegalArgumentException("recordClass is required"); - } - - return new VolatileVectorStoreRecordCollectionOptions<>(recordClass, recordDefinition, - objectMapper); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/AnyTagEqualToFilterClause.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/AnyTagEqualToFilterClause.java deleted file mode 100644 index 81eea80b9..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/AnyTagEqualToFilterClause.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.filter; - -/** - * A filter clause that filters on any tag equal to a value. - */ -public class AnyTagEqualToFilterClause implements FilterClause { - - private final String fieldName; - private final Object value; - - /** - * Creates a new instance of the AnyTagEqualToFilterClause class. - * @param fieldName The field name to filter on. - * @param value The value to filter on. - */ - public AnyTagEqualToFilterClause(String fieldName, Object value) { - this.fieldName = fieldName; - this.value = value; - } - - /** - * Gets the field name to filter on. - * - * @return The field name to filter on. - */ - public String getFieldName() { - return fieldName; - } - - /** - * Gets the value. - * - * @return The value. - */ - public Object getValue() { - return value; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/EqualToFilterClause.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/EqualToFilterClause.java deleted file mode 100644 index c75b04dce..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/EqualToFilterClause.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.filter; - -/** - * A filter clause that filters on a field equal to a value. - */ -public class EqualToFilterClause implements FilterClause { - private final String fieldName; - private final Object value; - - /** - * Initializes a new instance of the EqualToFilterClause class. - * - * @param fieldName The field name to filter on. - * @param value The value to filter on. - */ - public EqualToFilterClause(String fieldName, Object value) { - this.fieldName = fieldName; - this.value = value; - } - - /** - * Gets the field name to filter on. - * - * @return The field name to filter on. - */ - public String getFieldName() { - return fieldName; - } - - /** - * Gets the value. - * - * @return The value. - */ - public Object getValue() { - return value; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterClause.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterClause.java deleted file mode 100644 index 8e9a6e603..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterClause.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.filter; - -/** - * A filter clause for a query. - */ -public interface FilterClause { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterMapping.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterMapping.java deleted file mode 100644 index 6483ab400..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/filter/FilterMapping.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.filter; - -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; - -public interface FilterMapping { - /** - * Gets the filter string for the given vector search filter and record definition. - * - * @param filter The filter to get the filter string for. - * @param recordDefinition The record definition to get the filter string for. - * @return The filter string. - */ - String getFilter(VectorSearchFilter filter, VectorStoreRecordDefinition recordDefinition); - - /** - * Gets the filter string for the given equal to filter clause. - * - * @param filterClause The equal to filter clause to get the filter string for. - * @return The filter string. - */ - String getEqualToFilter(EqualToFilterClause filterClause); - - /** - * Gets the filter string for the given any tag equal to filter clause. - * - * @param filterClause The any tag equal to filter clause to get the filter string for. - * @return The filter string. - */ - String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchResultMapper.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchResultMapper.java deleted file mode 100644 index 652d2474c..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchResultMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -/** - * Default implementation of {@link TextSearchResultMapper}. - */ -public class DefaultTextSearchResultMapper implements TextSearchResultMapper { - /** - * Maps a search result to a {@link TextSearchResult}. - * - * @param result The search result. - * @return The {@link TextSearchResult}. - */ - @Override - public TextSearchResult fromResultToTextSearchResult(Object result) { - return TextSearchResult.fromRecord(result); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchStringMapper.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchStringMapper.java deleted file mode 100644 index 5d9c05452..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/DefaultTextSearchStringMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -/** - * Default implementation of {@link TextSearchStringMapper}. - */ -public class DefaultTextSearchStringMapper implements TextSearchStringMapper { - /** - * Maps a search result to a string. - * - * @param result The search result. - * @return The string. - */ - @Override - public String fromResultToString(Object result) { - TextSearchResult textSearchResult = TextSearchResult.fromRecord(result); - return textSearchResult.getValue(); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/KernelSearchResults.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/KernelSearchResults.java deleted file mode 100644 index 233439770..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/KernelSearchResults.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * The search results. - * - * @param The type of the search results. - */ -public class KernelSearchResults { - private final List results; - private final long totalCount; - private final Map metadata; - - /** - * Creates a new instance of the KernelSearchResults class. - * - * @param results The search results. - */ - public KernelSearchResults(List results) { - this(results, results.size(), Collections.emptyMap()); - } - - /** - * Creates a new instance of the KernelSearchResults class. - * - * @param results The search results. - * @param totalCount The total count of search results. - * @param metadata The metadata. - */ - public KernelSearchResults(List results, long totalCount, - Map metadata) { - this.results = Collections.unmodifiableList(results); - this.totalCount = totalCount; - this.metadata = Collections.unmodifiableMap(metadata); - } - - /** - * Gets the total count of search results. - * This value represents the total number of results that are available for the current query and not the number of results being returned. - * - * @return The total count of search results. - */ - public long getTotalCount() { - return totalCount; - } - - /** - * Gets the search results. - * - * @return The search results. - */ - public List getResults() { - return results; - } - - /** - * Gets the metadata associated with the search results. - * - * @return The metadata. - */ - public Map getMetadata() { - return metadata; - } - -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearch.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearch.java deleted file mode 100644 index 04ca24ade..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearch.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import reactor.core.publisher.Mono; - -public interface TextSearch { - - /** - * Perform a search for content related to the specified query and return String values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - Mono> searchAsync(String query, TextSearchOptions options); - - /** - * Perform a search for content related to the specified query and return TextSearchResult values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - Mono> getTextSearchResultsAsync(String query, - TextSearchOptions options); - - /** - * Perform a search for content related to the specified query and return Object values representing the search results. - * - * @param query The text to search for. - * @param options The search options. - * @return The search results. - */ - Mono> getSearchResultsAsync(String query, - TextSearchOptions options); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchFilter.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchFilter.java deleted file mode 100644 index 8e4484482..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchFilter.java +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.filter.FilterClause; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Represents a text search filter. - */ -public class TextSearchFilter { - - private final List filterClauses; - - /** - * Creates a new instance of the TextSearchFilter class. - */ - public TextSearchFilter() { - this(Collections.emptyList()); - } - - /** - * Creates a new instance of the TextSearchFilter class. - * - * @param filterClauses The filter clauses. - */ - public TextSearchFilter(List filterClauses) { - this.filterClauses = Collections.unmodifiableList(filterClauses); - } - - /** - * Gets the filter clauses. - * - * @return The filter clauses. - */ - public List getFilterClauses() { - return filterClauses; - } - - /** - * Creates a new instance of the {@link Builder} class. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * The builder for the {@link TextSearchFilter} class. - */ - public static class Builder { - private final List filterClauses = new ArrayList<>(); - - /** - * Adds an EqualToFilterClause to the filter. - * - * @param fieldName The field name to filter on. - * @param value The value. - * @return The builder. - */ - public Builder equalTo(String fieldName, Object value) { - filterClauses.add(new EqualToFilterClause(fieldName, value)); - return this; - } - - /** - * Builds the filter. - * - * @return The filter. - */ - public TextSearchFilter build() { - return new TextSearchFilter(filterClauses); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchOptions.java deleted file mode 100644 index 816885815..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchOptions.java +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -/** - * Represents the options for a text search. - */ -public class TextSearchOptions { - - /** - * The default number of search results to return. - */ - public static final int DEFAULT_TOP = 3; - private final boolean includeTotalCount; - private final int top; - private final int skip; - private final TextSearchFilter filter; - - /** - * Creates a new instance of the TextSearchOptions class with default values. - * - * @return A new instance of the TextSearchOptions class with default values. - */ - public static TextSearchOptions createDefault() { - return new TextSearchOptions(false, DEFAULT_TOP, 0, null); - } - - /** - * Creates a new instance of the TextSearchOptions class. - * - * @param includeTotalCount A value indicating whether to include the total count of search results. - * @param top The limit of the number of results to return. - * @param skip The offset of the results to return. - * @param filter The search filter. - */ - TextSearchOptions(boolean includeTotalCount, int top, int skip, TextSearchFilter filter) { - this.includeTotalCount = includeTotalCount; - this.top = top; - this.skip = skip; - this.filter = filter; - } - - /** - * Gets a value indicating whether to include the total count of search results. - * - * @return A value indicating whether to include the total count of search results. - */ - public boolean isIncludeTotalCount() { - return includeTotalCount; - } - - /** - * Gets the limit of the number of results to return. - * - * @return The limit of the number of results to return. - */ - public int getTop() { - return top; - } - - /** - * Gets the offset of the results to return. - * - * @return The offset of the results to return. - */ - public int getSkip() { - return skip; - } - - /** - * Gets the search filter. - * - * @return The search filter. - */ - public TextSearchFilter getFilter() { - return filter; - } - - /** - * Creates a new instance of the {@link Builder} class. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * The builder for the {@link TextSearchOptions} class. - */ - public static class Builder { - private boolean includeTotalCount = false; - private int top = DEFAULT_TOP; - private int skip = 0; - private TextSearchFilter filter; - - /** - * Sets a value indicating whether to include the total count of search results. - * - * @param includeTotalCount A value indicating whether to include the total count of search results. - * @return The builder. - */ - public Builder withIncludeTotalCount(boolean includeTotalCount) { - this.includeTotalCount = includeTotalCount; - return this; - } - - /** - * Sets the limit of the number of results to return. - * - * @param top The limit of the number of results to return. - * @return The builder. - */ - public Builder withTop(int top) { - this.top = top; - return this; - } - - /** - * Sets the offset of the results to return. - * - * @param skip The offset of the results to return. - * @return The builder. - */ - public Builder withSkip(int skip) { - this.skip = skip; - return this; - } - - /** - * Sets the search filter. - * - * @param filter The search filter. - * @return The builder. - */ - public Builder withFilter(TextSearchFilter filter) { - this.filter = filter; - return this; - } - - /** - * Builds a new instance of the {@link TextSearchOptions} class. - * - * @return A new instance of the TextSearchOptions class. - */ - public TextSearchOptions build() { - return new TextSearchOptions(includeTotalCount, top, skip, filter); - } - } - -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResult.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResult.java deleted file mode 100644 index 2a6221f30..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResult.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import com.microsoft.semantickernel.exceptions.SKException; - -import java.lang.reflect.Field; - -/** - * Represents a text search result. - */ -public class TextSearchResult { - private final String name; - private final String value; - private final String link; - - /** - * Creates a new instance of the TextSearchResult class. - * - * @param name The name of the search result. - * @param value The value of the search result. - * @param link The link of the search result. - */ - TextSearchResult(String name, String value, String link) { - this.name = name; - this.value = value; - this.link = link; - } - - /** - * Gets the name of the search result. - * - * @return The name of the search result. - */ - public String getName() { - return name; - } - - /** - * Gets the value of the search result. - * - * @return The value of the search result. - */ - public String getValue() { - return value; - } - - /** - * Gets the link of the search result. - * - * @return The link of the search result. - */ - public String getLink() { - return link; - } - - /** - * Creates a new instance of the {@link TextSearchResult} class from a record. - * The record should have fields annotated with {@link TextSearchResultName}, {@link TextSearchResultValue}, and {@link TextSearchResultLink}. - * - * @param record The record. - * @return The TextSearchResult. - */ - public static TextSearchResult fromRecord(Object record) { - String name = null, value = null, link = null; - - try { - for (Field field : record.getClass().getDeclaredFields()) { - if (field.isAnnotationPresent(TextSearchResultName.class)) { - if (name != null) { - throw new SKException("Multiple fields with @TextSearchResultName found"); - } - - field.setAccessible(true); - name = (String) field.get(record); - } - if (field.isAnnotationPresent(TextSearchResultValue.class)) { - if (value != null) { - throw new SKException("Multiple fields with @TextSearchResultValue found"); - } - - field.setAccessible(true); - value = (String) field.get(record); - } - if (field.isAnnotationPresent(TextSearchResultLink.class)) { - if (link != null) { - throw new SKException("Multiple fields with @TextSearchResultLink found"); - } - - field.setAccessible(true); - link = (String) field.get(record); - } - } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - - if (value == null) { - throw new SKException("No field with @TextSearchResultValue found"); - } - - return new TextSearchResult(name, value, link); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultLink.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultLink.java deleted file mode 100644 index fab7624e8..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultLink.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to mark a property on a record class as the link to the source data. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface TextSearchResultLink { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultMapper.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultMapper.java deleted file mode 100644 index 2fcbe37e9..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -/** - * Maps a search result to a {@link TextSearchResult}. - */ -public interface TextSearchResultMapper { - /** - * Maps a search result to a {@link TextSearchResult}. - * - * @param result The search result. - * @return The {@link TextSearchResult}. - */ - TextSearchResult fromResultToTextSearchResult(Object result); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultName.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultName.java deleted file mode 100644 index 77a3751ec..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultName.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to mark a property on a record class as the name of the source data. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface TextSearchResultName { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultValue.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultValue.java deleted file mode 100644 index 6b3dd568b..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchResultValue.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to mark a property on a record class as the value of the source data. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface TextSearchResultValue { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchStringMapper.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchStringMapper.java deleted file mode 100644 index c3afa4305..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/textsearch/TextSearchStringMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.textsearch; - -/** - * Maps a search result to a string. - */ -public interface TextSearchStringMapper { - /** - * Maps a search result to a string. - * - * @param result The search result. - * @return The string. - */ - String fromResultToString(Object result); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorOperations.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorOperations.java deleted file mode 100644 index ba86cb7b7..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorOperations.java +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordVectorField; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import com.microsoft.semantickernel.exceptions.SKException; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Operations for working with vectors. - */ -public final class VectorOperations { - - /** - * Calculates the cosine similarity of two vectors. The vectors must be equal in length and have - * non-zero norm. - * - * @param x First vector, which is not modified - * @param y Second vector, which is not modified - * @return The cosine similarity of the two vectors - */ - public static float cosineSimilarity(@Nonnull List x, @Nonnull List y) { - Objects.requireNonNull(x); - Objects.requireNonNull(y); - - if (x.size() != y.size()) { - throw new SKException("Vectors lengths must be equal"); - } - - float dotProduct = 0.0F; - float normX = 0.0F; - float normY = 0.0F; - - for (int i = 0; i < x.size(); i++) { - dotProduct += x.get(i) * y.get(i); - normX += x.get(i) * x.get(i); - normY += y.get(i) * y.get(i); - } - - if (normX == 0 || normY == 0) { - throw new SKException("Vectors cannot have zero norm"); - } - - return (dotProduct / (float) (Math.sqrt(normX) * Math.sqrt(normY))); - } - - /** - * Calculates the cosine distance of two vectors. The vectors must be equal in length and have - * non-zero norm. - * - * @param x First vector, which is not modified - * @param y Second vector, which is not modified - * @return The cosine distance of the two vectors - */ - public static double cosineDistance(List x, List y) { - return 1.0 - cosineSimilarity(x, y); - } - - /** - * Calculates the Euclidean distance between two vectors. - * - * @param x First vector, which is not modified - * @param y Second vector, which is not modified - * @return The Euclidean distance between the two vectors - */ - public static float euclideanDistance(@Nonnull List x, @Nonnull List y) { - Objects.requireNonNull(x); - Objects.requireNonNull(y); - - if (x.size() != y.size()) { - throw new SKException("Vectors lengths must be equal"); - } - - float sumOfSquaredDifferences = 0.0f; - - for (int i = 0; i < x.size(); ++i) { - float difference = x.get(i) - y.get(i); - sumOfSquaredDifferences += difference * difference; - } - - return (float) Math.sqrt(sumOfSquaredDifferences); - } - - /** - * Divides the elements of the vector by the divisor. - * - * @param vector Vector to divide, which is not modified - * @param divisor Divisor to apply to each element of the vector - * @return A new vector with the elements divided by the divisor - */ - public static List divide(@Nonnull List vector, float divisor) { - Objects.requireNonNull(vector); - if (Float.isNaN(divisor)) { - throw new SKException("Divisor cannot be NaN"); - } - if (divisor == 0f) { - throw new SKException("Divisor cannot be zero"); - } - - return vector.stream().map(x -> x / divisor).collect(Collectors.toList()); - } - - /** - * Calculates the dot product of two vectors. - * - * @param x First vector, which is not modified - * @param y Second vector, which is not modified - * @return The dot product of the two vectors - */ - public static float dot(@Nonnull List x, @Nonnull List y) { - Objects.requireNonNull(x); - Objects.requireNonNull(y); - - if (x.size() != y.size()) { - throw new SKException("Vectors lengths must be equal"); - } - - float result = 0; - for (int i = 0; i < x.size(); ++i) { - result += x.get(i) * y.get(i); - } - - return result; - } - - /** - * Calculates the Euclidean length of a vector. - * - * @param vector Vector to calculate the length of, which is not modified - * @return The Euclidean length of the vector - */ - public static float euclideanLength(@Nonnull List vector) { - Objects.requireNonNull(vector); - return (float) Math.sqrt(dot(vector, vector)); - } - - /** - * Multiplies the elements of the vector by the multiplier. - * - * @param vector Vector to multiply, which is not modified - * @param multiplier Multiplier to apply to each element of the vector - * @return A new vector with the elements multiplied by the multiplier - */ - public static List multiply(@Nonnull List vector, float multiplier) { - Objects.requireNonNull(vector); - if (Float.isNaN(multiplier)) { - throw new SKException("Multiplier cannot be NaN"); - } - if (Float.isInfinite(multiplier)) { - throw new SKException("Multiplier cannot be infinite"); - } - - return vector.stream().map(x -> x * multiplier).collect(Collectors.toList()); - } - - /** - * Normalizes the vector such that the Euclidean length is 1. - * - * @param vector Vector to normalize, which is not modified - * @return A new, normalized vector - */ - public static List normalize(@Nonnull List vector) { - Objects.requireNonNull(vector); - return divide(vector, euclideanLength(vector)); - } - - /** - * Performs an exact similarity search on a list of records using a vector field. - * - * @param records The records to search. - * @param vector The vector to search for. - * @param vectorField The vector field to use for the search. - * @param distanceFunction The distance function to use for the search. - * @param options The search options. - * @param The type of the records. - * @return The search results. - */ - public static List> exactSimilaritySearch( - List records, - List vector, - VectorStoreRecordVectorField vectorField, - DistanceFunction distanceFunction, - VectorSearchOptions options) { - List> results = new ArrayList<>(); - - for (Record record : records) { - List recordVector; - try { - String json = new ObjectMapper().writeValueAsString(record); - ArrayNode arrayNode = (ArrayNode) new ObjectMapper().readTree(json) - .get(vectorField.getEffectiveStorageName()); - - recordVector = Stream.iterate(0, i -> i + 1) - .limit(arrayNode.size()) - .map(i -> arrayNode.get(i).floatValue()) - .collect(Collectors.toList()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - - double score; - switch (distanceFunction) { - case COSINE_SIMILARITY: - score = cosineSimilarity(vector, recordVector); - break; - case COSINE_DISTANCE: - score = cosineDistance(vector, recordVector); - break; - case EUCLIDEAN_DISTANCE: - score = euclideanDistance(vector, recordVector); - break; - case DOT_PRODUCT: - score = dot(vector, recordVector); - break; - default: - throw new SKException("Unsupported distance function"); - } - - results.add(new VectorSearchResult<>(record, score)); - } - - Comparator> comparator = Comparator - .comparingDouble(VectorSearchResult::getScore); - // Higher scores are better - if (distanceFunction == DistanceFunction.COSINE_SIMILARITY - || distanceFunction == DistanceFunction.DOT_PRODUCT) { - comparator = comparator.reversed(); - } - - return results.stream() - .sorted(comparator) - .skip(options.getSkip()) - .limit(options.getTop()) - .collect(Collectors.toList()); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchFilter.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchFilter.java deleted file mode 100644 index 7006135f6..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchFilter.java +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -import com.microsoft.semantickernel.data.filter.EqualToFilterClause; -import com.microsoft.semantickernel.data.filter.FilterClause; -import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A vector search filter. - */ -public class VectorSearchFilter { - - /** - * Creates a new instance of the VectorSearchFilter class. - * - * @return A new instance of the VectorSearchFilter class. - */ - public static VectorSearchFilter createDefault() { - return new VectorSearchFilter(); - } - - private final List filterClauses; - - /** - * Creates a new instance of the VectorSearchFilter class. - */ - public VectorSearchFilter() { - this(Collections.emptyList()); - } - - /** - * Creates a new instance of the VectorSearchFilter class. - * - * @param filterClauses The filter clauses. - */ - public VectorSearchFilter(List filterClauses) { - this.filterClauses = Collections.unmodifiableList(filterClauses); - } - - /** - * Gets the filter clauses. - * - * @return The filter clauses. - */ - public List getFilterClauses() { - return filterClauses; - } - - /** - * Creates a {@link Builder} for the VectorSearchFilter class. - * - * @return A new instance of the VectorSearchFilter Builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for the VectorSearchFilter class. - */ - public static class Builder { - private final List filterClauses = new ArrayList<>(); - - /** - * Adds an EqualToFilterClause to the filter. - * - * @param fieldName The field name to filter on. - * @param value The value. - * @return The builder. - */ - public Builder equalTo(String fieldName, Object value) { - filterClauses.add(new EqualToFilterClause(fieldName, value)); - return this; - } - - /** - * Adds an AnyTagEqualToFilterClause to the filter. - * - * @param fieldName The field name to filter on. - * @param value The value. - * @return The builder. - */ - public Builder anyTagEqualTo(String fieldName, Object value) { - filterClauses.add(new AnyTagEqualToFilterClause(fieldName, value)); - return this; - } - - /** - * Builds the VectorSearchFilter. - * - * @return The VectorSearchFilter. - */ - public VectorSearchFilter build() { - return new VectorSearchFilter(filterClauses); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResult.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResult.java deleted file mode 100644 index e1f26beef..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResult.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -/** - * Represents a vector search result. - * @param The type of the record. - */ -public class VectorSearchResult { - private final Record record; - private final double score; - - /** - * Creates a new instance of VectorSearchResult. - * - * @param record The record. - * @param score The score. - */ - public VectorSearchResult(Record record, double score) { - this.record = record; - this.score = score; - } - - /** - * Gets the record. - * - * @return The record. - */ - public Record getRecord() { - return record; - } - - /** - * Gets the score. - * - * @return The score. - */ - public double getScore() { - return score; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResults.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResults.java deleted file mode 100644 index ad926e8f2..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorSearchResults.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * The search results. - * - * @param The type of the search results. - */ -public class VectorSearchResults { - - private final long totalCount; - private final List> results; - private final Map metadata; - - /** - * Creates a new instance of the VectorSearchResults class. - * - * @param results The search results. - */ - public VectorSearchResults(List> results) { - this(results, results.size(), Collections.emptyMap()); - } - - /** - * Creates a new instance of the VectorSearchResults class. - * - * @param results The search results. - * @param totalCount The total count of search results. - * @param metadata The metadata. - */ - public VectorSearchResults(List> results, long totalCount, - Map metadata) { - this.results = Collections.unmodifiableList(results); - this.totalCount = totalCount; - this.metadata = Collections.unmodifiableMap(metadata); - } - - /** - * Gets the total count of search results. - * This value represents the total number of results that are available for the current query and not the number of results being returned. - * - * @return The total count of search results. - */ - public long getTotalCount() { - return totalCount; - } - - /** - * Gets the search results. - * - * @return The search results. - */ - public List> getResults() { - return results; - } - - /** - * Gets the metadata associated with the search results. - * - * @return The metadata. - */ - public Map getMetadata() { - return metadata; - } - -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizableTextSearch.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizableTextSearch.java deleted file mode 100644 index df4d38a81..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizableTextSearch.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import reactor.core.publisher.Mono; - -/** - * A vectorizable text search. - * - * @param The record type. - */ -public interface VectorizableTextSearch { - /** - * Vectorizable text search. This method searches for records that are similar to the given text. - * - * @param searchText The text to search with. - * @param options The options to use for the search. - * @return VectorSearchResults. - */ - Mono> searchAsync(String searchText, - VectorSearchOptions options); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizedSearch.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizedSearch.java deleted file mode 100644 index a8b61b1a1..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorsearch/VectorizedSearch.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorsearch; - -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import reactor.core.publisher.Mono; - -import java.util.List; - -/** - * A vectorized search. - * - * @param The record type. - */ -public interface VectorizedSearch { - - /** - * Vectorized search. This method searches for records that are similar to the given vector. - * - * @param vector The vector to search with. - * @param options The options to use for the search. - * @return Vector search results. - */ - Mono> searchAsync(List vector, - VectorSearchOptions options); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStore.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStore.java deleted file mode 100644 index de548be40..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStore.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage; - -import java.util.List; -import javax.annotation.Nonnull; - -import reactor.core.publisher.Mono; - -/** - * Represents a vector store. - */ -public interface VectorStore { - - /** - * Gets a collection from the vector store. - * - * @param collectionName The name of the collection. - * @param options The options for the collection. - * @param The key type. - * @param The record type. - * @return The collection. - */ - VectorStoreRecordCollection getCollection( - @Nonnull String collectionName, - @Nonnull VectorStoreRecordCollectionOptions options); - - /** - * Gets the names of all collections in the vector store. - * - * @return A list of collection names. - */ - Mono> getCollectionNamesAsync(); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollection.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollection.java deleted file mode 100644 index 1eb6124dd..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollection.java +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage; - -import com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch; -import com.microsoft.semantickernel.data.vectorstorage.options.DeleteRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; -import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; -import java.util.List; -import reactor.core.publisher.Mono; - -/** - * Represents a collection of records in a vector store. - * - * @param The type of the key of the records in the collection. - * @param The type of the records in the collection. - */ -public interface VectorStoreRecordCollection extends VectorizedSearch { - - /** - * Gets the name of the collection. - * - * @return The name of the collection. - */ - String getCollectionName(); - - /** - * Checks if the collection exists in the store. - * - * @return A Mono emitting a boolean indicating if the collection exists. - */ - Mono collectionExistsAsync(); - - /** - * Creates the collection in the store. - * - * @return A Mono representing the completion of the creation operation. - */ - Mono> createCollectionAsync(); - - /** - * Creates the collection in the store if it does not exist. - * - * @return A Mono representing the completion of the creation operation. - */ - Mono> createCollectionIfNotExistsAsync(); - - /** - * Deletes the collection from the store. - * - * @return A Mono representing the completion of the deletion operation. - */ - Mono deleteCollectionAsync(); - - /** - * Gets a record from the store. - * - * @param key The key of the record to get. - * @param options The options for getting the record. - * @return A Mono emitting the record. - */ - Mono getAsync(Key key, GetRecordOptions options); - - /** - * Gets a batch of records from the store. - * - * @param keys The keys of the records to get. - * @param options The options for getting the records. - * @return A Mono emitting a list of records. - */ - Mono> getBatchAsync(List keys, GetRecordOptions options); - - /** - * Inserts or updates a record in the store. - * - * @param data The record to upsert. - * @param options The options for upserting the record. - * @return A Mono emitting the key of the upserted record. - */ - Mono upsertAsync(Record data, UpsertRecordOptions options); - - /** - * Inserts or updates a batch of records in the store. - * - * @param data The records to upsert. - * @param options The options for upserting the records. - * @return A Mono emitting a list of keys of the upserted records. - */ - Mono> upsertBatchAsync(List data, UpsertRecordOptions options); - - /** - * Deletes a record from the store. - * - * @param key The key of the record to delete. - * @param options The options for deleting the record. - * @return A Mono representing the completion of the deletion operation. - */ - Mono deleteAsync(Key key, DeleteRecordOptions options); - - /** - * Deletes a batch of records from the store. - * - * @param keys The keys of the records to delete. - * @param options The options for deleting the records. - * @return A Mono representing the completion of the deletion operation. - */ - Mono deleteBatchAsync(List keys, DeleteRecordOptions options); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollectionOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollectionOptions.java deleted file mode 100644 index 926bd984d..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordCollectionOptions.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage; - -import com.microsoft.semantickernel.data.vectorstorage.definition.VectorStoreRecordDefinition; - -/** - * Represents the options for a collection of vector store records. - * - * @param the type of the key - * @param the type of the record - */ -public interface VectorStoreRecordCollectionOptions { - /** - * Gets the key class. - * - * @return the key class - */ - Class getKeyClass(); - - /** - * Gets the record class. - * - * @return the record class - */ - Class getRecordClass(); - - /** - * Gets the record definition. - * - * @return the record definition - */ - VectorStoreRecordDefinition getRecordDefinition(); -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordMapper.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordMapper.java deleted file mode 100644 index 85b14d61f..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/VectorStoreRecordMapper.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage; - -import com.microsoft.semantickernel.data.vectorstorage.options.GetRecordOptions; - -import javax.annotation.Nullable; -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A mapper to convert between a record and a storage model. - * - * @param the record type - * @param the storage model type - */ -public class VectorStoreRecordMapper { - @Nullable - private final Function recordToStorageModelMapper; - private final BiFunction storageModelToRecordMapper; - - /** - * Constructs a new instance of the VectorStoreRecordMapper. - * - * @param recordToStorageModelMapper the function to convert a record to a storage model - * @param storageModelToRecordMapper the function to convert a storage model to a record - */ - protected VectorStoreRecordMapper( - @Nullable Function recordToStorageModelMapper, - BiFunction storageModelToRecordMapper) { - this.recordToStorageModelMapper = recordToStorageModelMapper; - this.storageModelToRecordMapper = storageModelToRecordMapper; - } - - /** - * Gets the function to convert a record to a storage model. - * - * @return the function to convert a record to a storage model - */ - @Nullable - public Function getRecordToStorageModelMapper() { - return recordToStorageModelMapper; - } - - /** - * Gets the function to convert a storage model to a record. - * - * @return the function to convert a storage model to a record - */ - public BiFunction getStorageModelToRecordMapper() { - return storageModelToRecordMapper; - } - - /** - * Converts a record to a storage model. - * - * @param record the record to convert - * @return the storage model - */ - public StorageModel mapRecordToStorageModel(Record record) { - return getRecordToStorageModelMapper().apply(record); - } - - /** - * Converts a storage model to a record. - * - * @param storageModel the storage model to convert - * @param options the options - * @return the record - */ - public Record mapStorageModelToRecord(StorageModel storageModel, GetRecordOptions options) { - return getStorageModelToRecordMapper().apply(storageModel, options); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordData.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordData.java deleted file mode 100644 index 4043af26d..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordData.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Represents a data field in a record. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface VectorStoreRecordData { - /** - * Storage name of the field. - * This value is only used when JSON Serialization using Jackson is not supported in a VectorStore. - * When Jackson is supported, @JsonProperty should be used to specify an alternate field name in the storage database. - * @return The storage name of the field. - */ - String storageName() default ""; - - /** - * Whether the field is filterable. - * @return {@code true} if the field is filterable. - */ - boolean isFilterable() default false; - - /** - * Whether the field is full text searchable. - * @return {@code true} if the field is full text searchable. - */ - boolean isFullTextSearchable() default false; -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordKey.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordKey.java deleted file mode 100644 index 108b6a0c9..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordKey.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Represents the key field in a record. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface VectorStoreRecordKey { - /** - * Storage name of the field. - * @return The storage name of the field. - */ - String storageName() default ""; -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordVector.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordVector.java deleted file mode 100644 index dfce13522..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/annotations/VectorStoreRecordVector.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.annotations; - -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - -import javax.annotation.Nullable; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Represents a vector field in a record. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface VectorStoreRecordVector { - - /** - * Number of dimensions in the vector. - * @return The number of dimensions in the vector. - */ - int dimensions(); - - /** - * Storage name of the field. - * @return The storage name of the field. - */ - String storageName() default ""; - - /** - * Type of index to be used for the vector. - * @return The type of index to be used for the vector. - */ - @Nullable - IndexKind indexKind() default IndexKind.UNDEFINED; - - /** - * Distance function to be used for to compute the distance between vectors. - * @return The distance function to be used for to compute the distance between vectors. - */ - @Nullable - DistanceFunction distanceFunction() default DistanceFunction.UNDEFINED; - -} \ No newline at end of file diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/DistanceFunction.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/DistanceFunction.java deleted file mode 100644 index 1512db526..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/DistanceFunction.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -/** - * Distance functions for vector storage. - */ -public enum DistanceFunction { - /** - * Cosine (angular) similarity function. - */ - COSINE_SIMILARITY("cosineSimilarity"), - /** - * Cosine distance function. 1 - cosine similarity. - */ - COSINE_DISTANCE("cosineDistance"), - /** - * Dot product between two vectors. - */ - DOT_PRODUCT("dotProduct"), - /** - * Euclidean distance function. Also known as L2 distance. - */ - EUCLIDEAN_DISTANCE("euclidean"), - /** - * No distance function specified. It will default to the database's default distance function. - */ - UNDEFINED(null); - - private final String value; - - DistanceFunction(String value) { - this.value = value; - } - - /** - * Gets the function name. - * @return The function name. - */ - public String getValue() { - return value; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/IndexKind.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/IndexKind.java deleted file mode 100644 index 4372d6511..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/IndexKind.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -/** - * Represents the kind of index to use for a vector store. - */ -public enum IndexKind { - /** - * Hierarchical Navigable Small World, which performs an approximate nearest neighbour (ANN) search. - */ - HNSW("Hnsw"), - - /** - * Flat index, which performs an exact nearest neighbour search. - * Also referred to as exhaustive k nearest neighbor in some databases. - * High recall accuracy, but slower and more expensive than HNSW. - * Better with smaller datasets. - */ - FLAT("Flat"), - - /** - * Inverted file index, which performs an approximate nearest neighbour (ANN) search. - */ - IVFFLAT("IVFFlat"), - - /** - * No index specified. It will default to the database's default index. - */ - UNDEFINED(null); - - private final String value; - - IndexKind(String value) { - this.value = value; - } - - /** - * Gets the string value of the index kind. - * - * @return the string value of the index kind - */ - public String getValue() { - return value; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDataField.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDataField.java deleted file mode 100644 index 713cae29f..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDataField.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents a data field in a record. - */ -public class VectorStoreRecordDataField extends VectorStoreRecordField { - private final boolean isFilterable; - private final boolean isFullTextSearchable; - - /** - * Create a builder for the VectorStoreRecordDataField class. - * @return a new instance of the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new instance of the VectorStoreRecordDataField class. - * - * @param name the name of the field - * @param storageName the storage name of the field - * @param fieldType the field type - * @param isFilterable a value indicating whether the field is filterable - * @param isFullTextSearchable a value indicating whether the field is full text searchable - */ - public VectorStoreRecordDataField( - @Nonnull String name, - @Nullable String storageName, - @Nonnull Class fieldType, - boolean isFilterable, - boolean isFullTextSearchable) { - super(name, storageName, fieldType); - this.isFilterable = isFilterable; - this.isFullTextSearchable = isFullTextSearchable; - } - - public VectorStoreRecordDataField( - @Nonnull String name, - @Nullable String storageName, - @Nonnull Class fieldType, - @Nonnull Class fieldSubType, - boolean isFilterable, - boolean isFullTextSearchable) { - super(name, storageName, fieldType, fieldSubType); - this.isFilterable = isFilterable; - this.isFullTextSearchable = isFullTextSearchable; - } - - /** - * Gets a value indicating whether the field is filterable. - * - * @return a value indicating whether the field is filterable - */ - public boolean isFilterable() { - return isFilterable; - } - - /** - * Gets a value indicating whether the field is full text searchable. - * - * @return a value indicating whether the field is full text searchable - */ - public boolean isFullTextSearchable() { - return isFullTextSearchable; - } - - /** - * Builder for the VectorStoreRecordDataField class. - */ - public static class Builder - extends VectorStoreRecordField.Builder { - private boolean isFilterable; - private boolean isFullTextSearchable; - - /** - * Sets a value indicating whether the field is filterable. - * - * @param isFilterable a value indicating whether the field is filterable - * @return the builder - */ - public Builder isFilterable(boolean isFilterable) { - this.isFilterable = isFilterable; - return this; - } - - /** - * Sets a value indicating whether the field is full text searchable. - * - * @param isFullTextSearchable a value indicating whether the field is full text searchable - * @return the builder - */ - public Builder isFullTextSearchable(boolean isFullTextSearchable) { - this.isFullTextSearchable = isFullTextSearchable; - return this; - } - - /** - * Builds a new instance of the VectorStoreRecordDataField class. - * - * @return a new instance of the VectorStoreRecordDataField class - */ - @Override - public VectorStoreRecordDataField build() { - if (name == null) { - throw new IllegalArgumentException("name is required"); - } - if (fieldType == null) { - throw new IllegalArgumentException("fieldType is required"); - } - - return new VectorStoreRecordDataField( - name, - storageName, - fieldType, - fieldSubType, - isFilterable, - isFullTextSearchable); - } - } - -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDefinition.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDefinition.java deleted file mode 100644 index abb061112..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordDefinition.java +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.exceptions.SKException; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Represents a definition of a vector store record. - */ -public class VectorStoreRecordDefinition { - - private final VectorStoreRecordKeyField keyField; - private final List dataFields; - private final List vectorFields; - - // Cached information - private final List nonVectorFields; - private final List allFields; - private final Map allFieldsMap; - - /** - * Gets the key field in the record definition. - * @return VectorStoreRecordKeyField - */ - public VectorStoreRecordKeyField getKeyField() { - return keyField; - } - - /** - * Gets the data fields in the record definition. - * @return List of VectorStoreRecordDataField - */ - public List getDataFields() { - return dataFields; - } - - /** - * Gets the vector fields in the record definition. - * - * @return List of VectorStoreRecordVectorField - */ - public List getVectorFields() { - return vectorFields; - } - - /** - * Gets all fields in the record definition. - * - * @return List of VectorStoreRecordField - */ - public List getAllFields() { - return allFields; - } - - /** - * Gets the non-vector fields in the record definition. - * - * @return List of VectorStoreRecordField - */ - public List getNonVectorFields() { - return nonVectorFields; - } - - /** - * Checks if the record definition contains a field with the specified name. - * - * @param fieldName The name of the field to check. - * @return boolean - */ - public boolean containsField(String fieldName) { - return allFieldsMap.containsKey(fieldName); - } - - /** - * Gets the field with the specified name. - * - * @param fieldName The name of the field to get. - * @return VectorStoreRecordField - */ - public VectorStoreRecordField getField(String fieldName) { - if (!allFieldsMap.containsKey(fieldName)) { - throw new SKException("Field not found: " + fieldName); - } - return allFieldsMap.get(fieldName); - } - - private VectorStoreRecordDefinition( - VectorStoreRecordKeyField keyField, - List dataFields, - List vectorFields) { - this.keyField = keyField; - this.dataFields = Collections.unmodifiableList(dataFields); - this.vectorFields = Collections.unmodifiableList(vectorFields); - this.nonVectorFields = Collections - .unmodifiableList(Stream.concat(Stream.of(keyField), dataFields.stream()) - .collect(Collectors.toList())); - this.allFields = Collections - .unmodifiableList(Stream.concat(nonVectorFields.stream(), vectorFields.stream()) - .collect(Collectors.toList())); - this.allFieldsMap = Collections.unmodifiableMap(allFields.stream() - .collect(Collectors.toMap(VectorStoreRecordField::getName, p -> p))); - } - - private static VectorStoreRecordDefinition checkFields( - List keyFields, - List dataFields, - List vectorFields) { - if (keyFields.size() != 1) { - throw new IllegalArgumentException("Exactly one key field is required"); - } - - return new VectorStoreRecordDefinition(keyFields.iterator().next(), dataFields, - vectorFields); - } - - /** - * Create a VectorStoreRecordDefinition from a collection of fields. - * - * @param fields The fields to create the definition from. - * @return VectorStoreRecordDefinition - */ - public static VectorStoreRecordDefinition fromFields(List fields) { - List keyFields = fields.stream() - .filter(p -> p instanceof VectorStoreRecordKeyField) - .map(p -> (VectorStoreRecordKeyField) p) - .collect(Collectors.toList()); - - List dataFields = fields.stream() - .filter(p -> p instanceof VectorStoreRecordDataField) - .map(p -> (VectorStoreRecordDataField) p) - .collect(Collectors.toList()); - - List vectorFields = fields.stream() - .filter(p -> p instanceof VectorStoreRecordVectorField) - .map(p -> (VectorStoreRecordVectorField) p) - .collect(Collectors.toList()); - - return checkFields(keyFields, dataFields, vectorFields); - } - - /** - * Create a VectorStoreRecordDefinition from a model. - * - * @param recordClass The model class to create the definition from. - * @return VectorStoreRecordDefinition - */ - public static VectorStoreRecordDefinition fromRecordClass(Class recordClass) { - List keyFields = new ArrayList<>(); - List dataFields = new ArrayList<>(); - List vectorFields = new ArrayList<>(); - - for (Field field : recordClass.getDeclaredFields()) { - String storageName = null; - if (field.isAnnotationPresent(JsonProperty.class)) { - storageName = field.getAnnotation(JsonProperty.class).value(); - } - - if (field.isAnnotationPresent(VectorStoreRecordKey.class)) { - VectorStoreRecordKey keyAttribute = field - .getAnnotation(VectorStoreRecordKey.class); - - if (storageName == null) { - storageName = keyAttribute.storageName().isEmpty() ? field.getName() - : keyAttribute.storageName(); - } - keyFields.add(VectorStoreRecordKeyField.builder() - .withName(field.getName()) - .withStorageName(storageName) - .withFieldType(field.getType()) - .build()); - } - - if (field.isAnnotationPresent(VectorStoreRecordData.class)) { - VectorStoreRecordData dataAttribute = field - .getAnnotation(VectorStoreRecordData.class); - - if (storageName == null) { - storageName = dataAttribute.storageName().isEmpty() ? field.getName() - : dataAttribute.storageName(); - } - dataFields.add(VectorStoreRecordDataField.builder() - .withName(field.getName()) - .withStorageName(storageName) - .withFieldType(field.getType(), - List.class.equals(field.getType()) - ? (Class) ((ParameterizedType) field.getGenericType()) - .getActualTypeArguments()[0] - : null) - .isFilterable(dataAttribute.isFilterable()) - .build()); - } - - if (field.isAnnotationPresent(VectorStoreRecordVector.class)) { - VectorStoreRecordVector vectorAttribute = field - .getAnnotation(VectorStoreRecordVector.class); - - if (storageName == null) { - storageName = vectorAttribute.storageName().isEmpty() ? field.getName() - : vectorAttribute.storageName(); - } - vectorFields.add(VectorStoreRecordVectorField.builder() - .withName(field.getName()) - .withStorageName(storageName) - .withFieldType(field.getType(), - List.class.equals(field.getType()) - ? (Class) ((ParameterizedType) field.getGenericType()) - .getActualTypeArguments()[0] - : null) - .withDimensions(vectorAttribute.dimensions()) - .withIndexKind(vectorAttribute.indexKind()) - .withDistanceFunction(vectorAttribute.distanceFunction()) - .build()); - } - } - - return checkFields(keyFields, dataFields, vectorFields); - } - - /** - * Validate that the record class contains only supported field types. - * @param fields The declared fields in the record class. - * @param supportedTypes The supported field types. - * @throws IllegalArgumentException if unsupported field types are found. - */ - public static void validateSupportedTypes(List fields, - Set> supportedTypes) { - Set> unsupportedTypes = new HashSet<>(); - for (VectorStoreRecordField field : fields) { - if (!supportedTypes.contains(field.getFieldType())) { - unsupportedTypes.add(field.getFieldType()); - } - } - if (!unsupportedTypes.isEmpty()) { - throw new IllegalArgumentException( - String.format( - "Unsupported field types found in record class: %s. Supported types: %s", - unsupportedTypes.stream().map(Class::getName).collect(Collectors.joining(", ")), - supportedTypes.stream().map(Class::getName).collect(Collectors.joining(", ")))); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordField.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordField.java deleted file mode 100644 index f777bd5c1..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordField.java +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents a field in a record. - */ -public class VectorStoreRecordField { - private final String name; - @Nullable - private final String storageName; - private final Class fieldType; - private final Class fieldSubType; - - /** - * Creates a new instance of the VectorStoreRecordField class. - * - * @param name the name of the field - * @param storageName the storage name of the field - * @param fieldType the field type - */ - public VectorStoreRecordField( - @Nonnull String name, - @Nullable String storageName, - @Nonnull Class fieldType) { - this.name = name; - this.storageName = storageName; - this.fieldType = fieldType; - this.fieldSubType = null; - } - - /** - * Creates a new instance of the VectorStoreRecordField class. - * - * @param name the name of the field - * @param storageName the storage name of the field - * @param fieldType the field type - * @param fieldSubType if the field type is a list, the type of - * the list elements, otherwise null - */ - public VectorStoreRecordField( - @Nonnull String name, - @Nullable String storageName, - @Nonnull Class fieldType, - @Nonnull Class fieldSubType) { - this.name = name; - this.storageName = storageName; - this.fieldType = fieldType; - this.fieldSubType = fieldSubType; - } - - /** - * Gets the name of the field. - * - * @return the name of the field - */ - public String getName() { - return name; - } - - /** - * Gets the storage name of the field. - * - * @return the storage name of the field - */ - public String getStorageName() { - return storageName; - } - - /** - * Gets the effective storage name of the field. - *

- * If the storage name is not set, the name of the field is returned. - * @return the effective storage name of the field - */ - public String getEffectiveStorageName() { - return storageName != null ? storageName : name; - } - - /** - * Gets the field type. - * - * @return the field type - */ - public Class getFieldType() { - return fieldType; - } - - public Class getFieldSubType() { - return fieldSubType; - } - - /** - * A builder for the VectorStoreRecordField class. - * @param the type of the field - * @param the type of the builder - */ - public abstract static class Builder> - implements SemanticKernelBuilder { - - @Nullable - protected String name; - @Nullable - protected String storageName; - @Nullable - protected Class fieldType; - - @Nullable - protected Class fieldSubType; - - /** - * Sets the name of the field. - * - * @param name the name of the field - * @return the builder - */ - public U withName(String name) { - this.name = name; - return (U) this; - } - - /** - * Sets the storage name of the field. - * - * @param storageName the storage name of the field - * @return the builder - */ - public U withStorageName(String storageName) { - this.storageName = storageName; - return (U) this; - } - - /** - * Sets the field type. - * - * @param fieldType the field type - * @return the builder - */ - public U withFieldType(Class fieldType) { - this.fieldType = fieldType; - return (U) this; - } - - public U withFieldType(Class fieldType, Class fieldSubType) { - this.fieldType = fieldType; - this.fieldSubType = fieldSubType; - return (U) this; - } - - /** - * Builds the field. - * - * @return the field - */ - @Override - public abstract T build(); - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordKeyField.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordKeyField.java deleted file mode 100644 index 9e2a70e7e..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordKeyField.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -/** - * Represents the key field in a record. - */ -public class VectorStoreRecordKeyField extends VectorStoreRecordField { - - /** - * Create a builder for the VectorStoreRecordKeyField class. - * @return a new instance of the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new instance of the VectorStoreRecordKeyField class. - * - * @param name the name of the field - * @param storageName the storage name of the field - * @param type the field type - */ - public VectorStoreRecordKeyField(String name, String storageName, Class type) { - super(name, storageName, type); - } - - /** - * A builder for the VectorStoreRecordKeyField class. - */ - public static class Builder - extends VectorStoreRecordField.Builder { - @Override - public VectorStoreRecordKeyField build() { - if (name == null) { - throw new IllegalArgumentException("name is required."); - } - if (fieldType == null) { - throw new IllegalArgumentException("fieldType is required."); - } - return new VectorStoreRecordKeyField(name, storageName, fieldType); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordVectorField.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordVectorField.java deleted file mode 100644 index b708d2fbb..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/definition/VectorStoreRecordVectorField.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.definition; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Represents a vector field in a record. - */ -public class VectorStoreRecordVectorField extends VectorStoreRecordField { - private final int dimensions; - private final IndexKind indexKind; - private final DistanceFunction distanceFunction; - - /** - * Create a builder for the VectorStoreRecordVectorField class. - * @return a new instance of the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new instance of the VectorStoreRecordVectorField class. - * - * @param name the name of the field - * @param storageName the storage name of the field - * @param fieldType the field type - * @param dimensions the number of dimensions in the vector - * @param indexKind the index kind - * @param distanceFunction the distance function - */ - public VectorStoreRecordVectorField( - @Nonnull String name, - @Nullable String storageName, - @Nonnull Class fieldType, - Class fieldSubType, - int dimensions, - @Nullable IndexKind indexKind, - @Nullable DistanceFunction distanceFunction) { - super(name, storageName, fieldType, fieldSubType); - this.dimensions = dimensions; - this.indexKind = indexKind == null ? IndexKind.UNDEFINED : indexKind; - this.distanceFunction = distanceFunction == null ? DistanceFunction.UNDEFINED - : distanceFunction; - } - - /** - * Gets the number of dimensions in the vector. - * - * @return the number of dimensions in the vector - */ - public int getDimensions() { - return dimensions; - } - - /** - * Gets the index kind. - * - * @return the index kind - */ - public IndexKind getIndexKind() { - return indexKind; - } - - /** - * Gets the distance function. - * - * @return the distance function - */ - public DistanceFunction getDistanceFunction() { - return distanceFunction; - } - - /** - * A builder for the VectorStoreRecordVectorField class. - */ - public static class Builder - extends VectorStoreRecordField.Builder { - private int dimensions; - private IndexKind indexKind = IndexKind.UNDEFINED; - private DistanceFunction distanceFunction = DistanceFunction.UNDEFINED; - - /** - * Sets the number of dimensions in the vector. - * - * @param dimensions the number of dimensions in the vector - * @return the builder - */ - public Builder withDimensions(int dimensions) { - this.dimensions = dimensions; - return this; - } - - /** - * Sets the index kind. - * - * @param indexKind the index kind - * @return the builder - */ - public Builder withIndexKind(IndexKind indexKind) { - this.indexKind = indexKind; - return this; - } - - /** - * Sets the distance function. - * - * @param distanceFunction the distance function - * @return the builder - */ - public Builder withDistanceFunction(DistanceFunction distanceFunction) { - this.distanceFunction = distanceFunction; - return this; - } - - /** - * Builds a new instance of the VectorStoreRecordVectorField class. - * - * @return a new instance of the VectorStoreRecordVectorField class - */ - @Override - public VectorStoreRecordVectorField build() { - if (name == null) { - throw new IllegalArgumentException("name is required"); - } - if (fieldType == null) { - throw new IllegalArgumentException("fieldType is required"); - } - if (dimensions <= 0) { - throw new IllegalArgumentException("dimensions must be greater than 0"); - } - - return new VectorStoreRecordVectorField(name, storageName, fieldType, fieldSubType, - dimensions, - indexKind, - distanceFunction); - } - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/DeleteRecordOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/DeleteRecordOptions.java deleted file mode 100644 index ed0dbb924..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/DeleteRecordOptions.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.options; - -/** - * Options for deleting a record. - */ -public class DeleteRecordOptions { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/GetRecordOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/GetRecordOptions.java deleted file mode 100644 index 74d2b0651..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/GetRecordOptions.java +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.options; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; - -/** - * Options for getting a record. - */ -public class GetRecordOptions { - - private final boolean includeVectors; - - private final boolean wildcardKeyMatching; - - /** - * Creates a new instance of the GetRecordOptions class. - * @param includeVectors A value indicating whether to include vectors in a response. - */ - public GetRecordOptions( - boolean includeVectors) { - this.includeVectors = includeVectors; - this.wildcardKeyMatching = false; - } - - /** - * Creates a new instance of the GetRecordOptions class. - * @param includeVectors A value indicating whether to include vectors in a response. - * @param wildcardKeyMatching A value indicating whether to use wildcard key matching. - */ - public GetRecordOptions( - boolean includeVectors, - boolean wildcardKeyMatching) { - this.includeVectors = includeVectors; - this.wildcardKeyMatching = wildcardKeyMatching; - } - - /** - * Gets whether to use wildcard key matching. - * @return {@code true} if wildcard key matching is used; otherwise, {@code false}. - */ - public boolean isWildcardKeyMatching() { - return wildcardKeyMatching; - } - - /** - * Creates a new builder. - * - * @return the builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for GetRecordOptions. - */ - public static class Builder implements SemanticKernelBuilder { - - private boolean includeVectors; - private boolean wildcardKeyMatching = false; - - /** - * Sets whether to include vectors. - * - * @param includeVectors whether to include vectors - * @return GetRecordOptions.Builder - */ - public Builder includeVectors(boolean includeVectors) { - this.includeVectors = includeVectors; - return this; - } - - /** - * Sets whether to use wildcard key matching. Default is false. Wildcard key matching allows - * for matching multiple ids, for instance using "LIKE 'a%'" on a SQL query. - *

- * NOTE: Currently this is only supported by the SQL connectors. - * - * @param wildcardKeyMatching whether to use wildcard key matching - * @return GetRecordOptions.Builder - */ - public Builder setWildcardKeyMatching(boolean wildcardKeyMatching) { - this.wildcardKeyMatching = wildcardKeyMatching; - return this; - } - - /** - * Builds the options. - * - * @return GetRecordOptions - */ - @Override - public GetRecordOptions build() { - return new GetRecordOptions(includeVectors, wildcardKeyMatching); - } - } - - /** - * Gets whether to include vectors. - * - * @return whether to include vectors - */ - public boolean isIncludeVectors() { - return includeVectors; - } -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/UpsertRecordOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/UpsertRecordOptions.java deleted file mode 100644 index a0a9325b5..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/UpsertRecordOptions.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.options; - -/** - * Options for upserting a record. - */ -public class UpsertRecordOptions { -} diff --git a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/VectorSearchOptions.java b/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/VectorSearchOptions.java deleted file mode 100644 index 53ef59dd0..000000000 --- a/semantickernel-api-data/src/main/java/com/microsoft/semantickernel/data/vectorstorage/options/VectorSearchOptions.java +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data.vectorstorage.options; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; - -import javax.annotation.Nullable; - -/** - * Options for a vector search. - */ -public class VectorSearchOptions { - - /** - * The default limit of the number of results to return. - */ - public static final int DEFAULT_TOP = 3; - - /** - * Creates a new instance of the VectorSearchOptions class with default values. - * - * @param vectorFieldName The name of the vector field. - * @return A new instance of the VectorSearchOptions class with default values. - */ - public static VectorSearchOptions createDefault(String vectorFieldName) { - return VectorSearchOptions.builder() - .withVectorFieldName(vectorFieldName).build(); - } - - @Nullable - private final VectorSearchFilter vectorSearchFilter; - @Nullable - private final String vectorFieldName; - private final int top; - private final int skip; - private final boolean includeVectors; - private final boolean includeTotalCount; - - /** - * Creates a new instance of the VectorSearchOptions class. - * @param vectorSearchFilter The vector search filter. - * @param vectorFieldName The name of the vector field. - * @param top The limit of the number of results to return. - * @param skip The offset of the results to return. - * @param includeVectors A value indicating whether to include vectors in the results. - * @param includeTotalCount A value indicating whether to include the total count of the results. - */ - public VectorSearchOptions(VectorSearchFilter vectorSearchFilter, - String vectorFieldName, int top, int skip, boolean includeVectors, - boolean includeTotalCount) { - this.vectorSearchFilter = vectorSearchFilter; - this.vectorFieldName = vectorFieldName; - this.top = Math.max(1, top); - this.skip = Math.max(0, skip); - this.includeVectors = includeVectors; - this.includeTotalCount = includeTotalCount; - } - - /** - * Gets the vector search filter. - * - * @return The vector search filter. - */ - @Nullable - public VectorSearchFilter getVectorSearchFilter() { - return vectorSearchFilter; - } - - /** - * Gets the name of the vector field. - * - * @return The name of the vector field. - */ - @Nullable - public String getVectorFieldName() { - return vectorFieldName; - } - - /** - * Gets the limit of the number of results to return. - * - * @return The limit of the number of results to return. - */ - public int getTop() { - return top; - } - - /** - * Gets the offset of the results to return. - * - * @return The offset of the results to return. - */ - public int getSkip() { - return skip; - } - - /** - * Gets a value indicating whether to include vectors in the results. - * - * @return A value indicating whether to include vectors in the results. - */ - public boolean isIncludeVectors() { - return includeVectors; - } - - /** - * Gets a value indicating whether to include the total count of the results. - * - * @return A value indicating whether to include the total count of the results. - */ - public boolean isIncludeTotalCount() { - return includeTotalCount; - } - - /** - * Creates a new instance of the Builder class. - * - * @return A new instance of the Builder class. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for the VectorSearchOptions class. - */ - public static class Builder implements SemanticKernelBuilder { - private VectorSearchFilter vectorSearchFilter; - private String vectorFieldName; - private int top = DEFAULT_TOP; - private int skip = 0; - private boolean includeVectors = false; - private boolean includeTotalCount = false; - - /** - * Sets the vector search filter. - * @param vectorSearchFilter the vector search filter - * @return {@code this} builder - */ - public Builder withVectorSearchFilter( - VectorSearchFilter vectorSearchFilter) { - this.vectorSearchFilter = vectorSearchFilter; - return this; - } - - /** - * Sets the name of the vector field. - * @param vectorFieldName the name of the vector field - * @return {@code this} builder - */ - public Builder withVectorFieldName(String vectorFieldName) { - this.vectorFieldName = vectorFieldName; - return this; - } - - /** - * Sets the limit of the number of results to return. - * @param top the limit of the number of results to return - * @return {@code this} builder - */ - public Builder withTop(int top) { - this.top = top; - return this; - } - - /** - * Sets the offset of the results to return. - * @param skip the offset of the results to return - * @return {@code this} builder - */ - public Builder withSkip(int skip) { - this.skip = skip; - return this; - } - - /** - * Sets a value indicating whether to include vectors in the results. - * @param includeVectors a value indicating whether to include vectors in the results - * @return {@code this} builder - */ - public Builder withIncludeVectors(boolean includeVectors) { - this.includeVectors = includeVectors; - return this; - } - - /** - * Sets a value indicating whether to include the total count of the results. - * @param includeTotalCount a value indicating whether to include the total count of the results - * @return {@code this} builder - */ - public Builder withIncludeTotalCount(boolean includeTotalCount) { - this.includeTotalCount = includeTotalCount; - return this; - } - - /** - * Builds a new instance of the VectorSearchOptions class. - * @return a new instance of the VectorSearchOptions class - */ - @Override - public VectorSearchOptions build() { - return new VectorSearchOptions(vectorSearchFilter, vectorFieldName, top, skip, - includeVectors, includeTotalCount); - } - } -} diff --git a/semantickernel-api-exceptions/pom.xml b/semantickernel-api-exceptions/pom.xml deleted file mode 100644 index b07b001c0..000000000 --- a/semantickernel-api-exceptions/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - Semantic Kernel Exceptions API - Defines the public interface for the Semantic Kernel Exceptions - - - - com.microsoft.semantic-kernel - semantickernel-api-localization - provided - - - com.google.code.findbugs - jsr305 - provided - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/AIException.java b/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/AIException.java deleted file mode 100644 index ac6290d6f..000000000 --- a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/AIException.java +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.exceptions; - -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * AI logic exception - */ -public class AIException extends SKException { - - /** - * Error code - */ - @Nonnull - private final ErrorCodes errorCode; - - /** - * Initializes a new instance of the {@link AIException} class. - * - * @param error The error code. - */ - public AIException(@Nonnull ErrorCodes error) { - this(error, null, null); - } - - /** - * Initializes a new instance of the {@link AIException} class. - * - * @param errorCode The error code. - * @param message The message. - */ - public AIException(@Nonnull ErrorCodes errorCode, @Nullable String message) { - this(errorCode, message, null); - } - - /** - * Initializes a new instance of the {@link AIException} class. - * - * @param errorCode The error code. - * @param message The message. - * @param innerException The cause of the exception. - */ - public AIException( - @Nonnull ErrorCodes errorCode, - @Nullable String message, - @Nullable Throwable innerException) { - super(formatDefaultMessage(errorCode.getMessage(), message), innerException); - this.errorCode = errorCode; - } - - /** - * Gets the error code. - * - * @return The error code. - */ - public ErrorCodes getErrorCode() { - return errorCode; - } - - /** - * Error codes - */ - public enum ErrorCodes { - /** - * Unknown error. - */ - UNKNOWN_ERROR(SemanticKernelResources.getString("unknown.error")), - - /** - * No response. - */ - NO_RESPONSE(SemanticKernelResources.getString("no.response")), - /** - * Access denied. - */ - ACCESS_DENIED(SemanticKernelResources.getString("access.is.denied")), - - /** - * Invalid request. - */ - INVALID_REQUEST(SemanticKernelResources.getString("the.request.was.invalid")), - /** - * Invalid response. - */ - INVALID_RESPONSE_CONTENT( - SemanticKernelResources.getString("the.content.of.the.response.was.invalid")), - - /** - * Throttling. - */ - THROTTLING(SemanticKernelResources.getString("the.request.was.throttled")), - /** - * Request timeout. - */ - REQUEST_TIMEOUT(SemanticKernelResources.getString("the.request.timed.out")), - - /** - * Service error. - */ - SERVICE_ERROR(SemanticKernelResources.getString("there.was.an.error.in.the.service")), - - /** - * Model not available. - */ - MODEL_NOT_AVAILABLE( - SemanticKernelResources.getString("the.requested.model.is.not.available")), - - /** - * Invalid configuration. - */ - INVALID_CONFIGURATION( - SemanticKernelResources.getString("the.supplied.configuration.was.invalid")), - /** - * Function type not supported. - */ - FUNCTION_TYPE_NOT_SUPPORTED( - SemanticKernelResources.getString("the.function.is.not.supported")); - - private final String message; - - ErrorCodes(String message) { - this.message = message; - } - - /** - * Gets the error message. - * - * @return The error message. - */ - public String getMessage() { - return message; - } - } -} diff --git a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/ConfigurationException.java b/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/ConfigurationException.java deleted file mode 100644 index e716f1fb7..000000000 --- a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/ConfigurationException.java +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.exceptions; - -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * An exception that is thrown when there is an error with the Semantic Kernel configuration. - */ -public class ConfigurationException extends SKCheckedException { - - /** - * Error code. - */ - @Nonnull - private final ErrorCodes errorCode; - - /** - * Creates a new instance of the {@link ConfigurationException} class. - * - * @param error the error code - */ - public ConfigurationException(@Nonnull ErrorCodes error) { - this(error, null, null); - } - - /** - * Creates a new instance of the {@link ConfigurationException} class. - * - * @param errorCode the error code - * @param message the message - */ - public ConfigurationException(@Nonnull ErrorCodes errorCode, @Nullable String message) { - this(errorCode, message, null); - } - - /** - * Creates a new instance of the {@link ConfigurationException} class. - * - * @param errorCode the error code - * @param message the message - * @param innerException the inner exception - */ - public ConfigurationException( - @Nonnull ErrorCodes errorCode, - @Nullable String message, - @Nullable Throwable innerException) { - super(formatDefaultMessage(errorCode.getMessage(), message), innerException); - this.errorCode = errorCode; - } - - /** - * Gets the error code. - * - * @return the error code - */ - public ErrorCodes getErrorCode() { - return errorCode; - } - - /** - * ErrorCodes for this exception. - */ - public enum ErrorCodes { - /** - * Unknown error - */ - UNKNOWN_ERROR(SemanticKernelResources.getString("unknown.error")), - - /** - * Could not find configuration file - */ - CONFIGURATION_NOT_FOUND( - SemanticKernelResources.getString("could.not.find.configuration.file")), - - /** - * Could not parse or load configuration file - */ - COULD_NOT_READ_CONFIGURATION( - SemanticKernelResources.getString("could.not.parse.or.load.configuration.file")), - - /** - * Could not find any valid configuration settings - */ - NO_VALID_CONFIGURATIONS_FOUND( - SemanticKernelResources.getString("could.not.find.any.valid.configuration.settings")), - - /** - * Could not find value for configuration key - */ - VALUE_NOT_FOUND( - SemanticKernelResources.getString("could.not.find.value.for.configuration.key")); - - private final String message; - - ErrorCodes(String message) { - this.message = message; - } - - /** - * Gets the message for the error code. - * - * @return the message for the error code - */ - public String getMessage() { - return message; - } - - /** - * Format the message with the given parameter. - * - * @param param helpful information - * @return the formatted message - */ - public String getMessage(String param) { - return String.format(message, param); - } - } -} diff --git a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKCheckedException.java b/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKCheckedException.java deleted file mode 100644 index 073906920..000000000 --- a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKCheckedException.java +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.exceptions; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Provides the base exception from which all CHECKED Semantic Kernel exceptions derive. - */ -public class SKCheckedException extends Exception { - - /** - * Initializes a new instance of the {@code SKCheckedException} class with a default message. - */ - protected SKCheckedException() { - super(); - } - - /** - * Initializes a new instance of the {@code SKCheckedException} class with its message set to - * {@code message}. - * - * @param message A string that describes the error. - */ - public SKCheckedException(@Nullable String message) { - super(message); - } - - /** - * Initializes a new instance of the {@code SKCheckedException} class with its message set to - * {@code message}. - * - * @param message A string that describes the error. - * @param cause The exception that is the cause of the current exception. - */ - public SKCheckedException(@Nullable String message, @Nullable Throwable cause) { - super(message, cause); - } - - /** - * Initializes a new instance of the {@code SKCheckedException} class with its - * message set to {@code null} and the cause set to {@code e}. - * - * @param cause The exception that is the cause of the current exception. - */ - public SKCheckedException(Throwable cause) { - super(cause); - } - - /** - * Forms a checked exception, if the exception is already an SK exception, it - * will be unwrapped - * and the cause extracted. - * - * @param message The message to be displayed - * @param cause The exception that is the cause of the current exception. - * @return A checked exception - */ - public static SKCheckedException build( - String message, - @Nullable Exception cause) { - - if (cause == null) { - return new SKCheckedException(message); - } - - Throwable wrappedCause = cause.getCause(); - - if ((cause instanceof SKCheckedException || cause instanceof SKException) - && wrappedCause != null) { - return new SKCheckedException(message, wrappedCause); - } else { - return new SKCheckedException(message, cause); - } - } - - /** - * Translate the error code into a default message format. - * - * @param errorMessage The error message from an error code - * @param message The message from the code which throws the exception - * @return A formatted message - */ - protected static String formatDefaultMessage( - @Nonnull String errorMessage, @Nullable String message) { - return SKException.formatDefaultMessage(errorMessage, message); - } -} diff --git a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKException.java b/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKException.java deleted file mode 100644 index 3f14a2f5c..000000000 --- a/semantickernel-api-exceptions/src/main/java/com/microsoft/semantickernel/exceptions/SKException.java +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.exceptions; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Provides the base exception from which all Semantic Kernel exceptions derive. - */ -public class SKException extends RuntimeException { - - /** - * Initializes a new instance of the {@code SKException} class with a default message. - */ - protected SKException() { - super(); - } - - /** - * Initializes a new instance of the {@code SKException} class with its message set to - * {@code message}. - * - * @param message A string that describes the error. - */ - public SKException(@Nullable String message) { - super(message); - } - - /** - * Initializes a new instance of the {@code SKException} class with its message set to - * {@code message}. - * - * @param message A string that describes the error. - * @param cause The exception that is the cause of the current exception. - */ - public SKException(@Nullable String message, @Nullable Throwable cause) { - super(message, cause); - } - - /** - * Initializes a new instance of the {@code SKException} class with its - * message set to {@code null} and the cause set to {@code e}. - * - * @param cause The exception that is the cause of the current exception. - */ - public SKException(Throwable cause) { - super(cause); - } - - /** - * Forms an unchecked exception, if the exception is already an SK exception, it will be - * unwrapped and the cause extracted. - * - * @param message The message to be displayed - * @param cause The exception that is the cause of the current exception. - * @return An unchecked exception - */ - public static SKException build( - String message, - @Nullable Exception cause) { - - if (cause == null) { - return new SKException(message); - } - - Throwable wrappedCause = cause.getCause(); - - if ((cause instanceof SKCheckedException || cause instanceof SKException) - && wrappedCause != null) { - return new SKException(message, wrappedCause); - } else { - return new SKException(message, cause); - } - } - - /** - * Translate the error code into a default message format. - * - * @param errorMessage The error message from an error code - * @param message The message from the code which throws the exception - * @return A formatted message - */ - protected static String formatDefaultMessage( - @Nonnull String errorMessage, @Nullable String message) { - return String.format("%s: %s", errorMessage, message); - } -} diff --git a/semantickernel-api-localization/pom.xml b/semantickernel-api-localization/pom.xml deleted file mode 100644 index f1c3c2467..000000000 --- a/semantickernel-api-localization/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-api-localization - Semantic Kernel Localization API - Defines the public interface for the Semantic Kernel Localization - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/semantickernel-api-localization/src/main/java/com/microsoft/semantickernel/localization/SemanticKernelResources.java b/semantickernel-api-localization/src/main/java/com/microsoft/semantickernel/localization/SemanticKernelResources.java deleted file mode 100644 index 2ebc9c415..000000000 --- a/semantickernel-api-localization/src/main/java/com/microsoft/semantickernel/localization/SemanticKernelResources.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.localization; - -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.PropertyResourceBundle; -import java.util.ResourceBundle; - -/** - * Provides access to the resources used by the Semantic Kernel. - */ -public class SemanticKernelResources { - - private static final String RESOURCE_BUNDLE_CLASS = "com.microsoft.semantickernel.localization.ResourceBundle"; - - private static ResourceBundle RESOURCE_BUNDLE; - private static Locale LOCALE; - - static { - LOCALE = setLocale(new Locale( - System.getProperty("semantickernel.locale", - String.valueOf(Locale.getDefault().getLanguage())))); - RESOURCE_BUNDLE = setResourceBundle(LOCALE); - } - - /** - * Load the localized resource bundle for the Semantic Kernel. - * If there is no resource bundle for the specified locale, the default - * resource bundle will be loaded. - * @param locale The locale to use. - * @return the resource bundle. - */ - public static ResourceBundle setResourceBundle(Locale locale) { - ResourceBundle resourceBundle; - try { - resourceBundle = PropertyResourceBundle.getBundle( - RESOURCE_BUNDLE_CLASS, locale); - } catch (MissingResourceException e) { - resourceBundle = PropertyResourceBundle.getBundle( - RESOURCE_BUNDLE_CLASS); - } - RESOURCE_BUNDLE = resourceBundle; - return resourceBundle; - } - - /** - * Set the locale for the Semantic Kernel. As a side effect, - * the localized resource bundle will be loaded. - * @param locale The locale to use. - * @return the locale. - */ - public static Locale setLocale(Locale locale) { - LOCALE = locale; - setResourceBundle(locale); - return locale; - } - - /** - * Get the string for the specified id from the resource bundle. - * @param id The id of the string. - * @param defaultValue The default value to return if the string is not found. - * @return the localized string, or the default value if the string is not found. - */ - public static String localize(String id, String defaultValue) { - if (RESOURCE_BUNDLE.containsKey(id)) { - return RESOURCE_BUNDLE.getString(id); - } else { - return defaultValue; - } - } - - /** - * Get the string for the specified id from the resource bundle. - * @param id The id of the string. - * @return the localized string, or the id if the string is not found. - */ - public static String getString(String id) { - return localize(id, id); - } - -} diff --git a/semantickernel-api-localization/src/main/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties b/semantickernel-api-localization/src/main/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties deleted file mode 100644 index cf1d17b0b..000000000 --- a/semantickernel-api-localization/src/main/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties +++ /dev/null @@ -1,57 +0,0 @@ -a.named.argument.must.have.a.name=A named argument must have a name -a.named.argument.must.have.a.value=A named argument must have a value -a.value.must.be.defined.using.either.single.quotes.or.double.quotes.not.both=A value must be defined using either single quotes or double quotes, not both -a.value.must.have.single.quotes.or.double.quotes.on.both.sides=A value must have single quotes or double quotes on both sides -a.variable.must.start.with.the.symbol=A variable must start with the symbol {} -a.variable.must.start.with.the.symbol.and.have.a.name=A variable must start with the symbol {} and have a name -access.is.denied=Access is denied -annotation.on.method.is.requesting.a.string=Annotation on method: {} is requesting a String which is not assignable to method type {}, possibly as the type argument has not been provided on the annotation. -attempting.to.modify.function.after.it.has.already.been.subscribed=Attempting to modify function {}.{} after it has already been subscribed to. This is not necessarily an error but may be an unusual pattern and indicate a potential bug. -could.not.find.any.valid.configuration.settings=Could not find any valid configuration settings -could.not.find.configuration.file=Could not find configuration file -could.not.find.value.for.configuration.key=Could not find value for configuration key -could.not.parse.or.load.configuration.file=Could not parse or load configuration file -error.building.generative.model=Error building generative model. -error.generating.chat.completion=Error generating chat completion -error.parsing.prompt=Error parsing prompt -failed.to.load.file.0=Failed to load file: {0} -failed.to.parse.config.file=Failed to parse config file {} -failed.to.read.file=Failed to read file -failed.to.read.file1=Failed to read file {} -for.the.function.0.1.the.unknown.parameter.name.was.detected=For the function {0}.{1}, the unknown parameter name was detected as "{2}" this is argument number {3} to the function, this indicates that the argument name for this function was removed during compilation and semantic-kernel is unable to determine the name of the parameter. To support this function the argument must be annotated with @SKFunctionParameters or @SKFunctionInputAttribute. Alternatively the function was invoked with a required context variable missing and no default value. -function.has.already.been.subscribed.to.this.is.not.necessarily.an.error.but.may.be.an.unusual.pattern=Function {}.{} has already been subscribed to. This is not necessarily an error but may be an unusual pattern. -functions.only.support.named.arguments.after.the.first.argument=Functions only support named arguments after the first argument. Argument {} is not named. -invalid.block.0=Invalid block{0} -no.config.for.in=No config for {} in {} -no.converter.found.for.to=No converter found for {} to {} -no.functions.found.in.class.this.can.be.caused.by=No functions found in class {}. This can be caused by DI frameworks that create proxies, or modules that are not making your methods visible. Try using: KernelPluginFactory.createFromObject(Class clazz, Object target, String pluginName). -no.response=No response -no.service.found.meeting.requirements=No service found meeting requirements -no.variable.type.explicitly.specified.by.calling.withresulttype.for.function=No variable type explicitly specified by calling 'withResultType' for function invocation: {}.{}. This may cause a runtime error (probably a ClassCastException) if the result type is not compatible with the expected type. -plugin.already.exists.overwriting.existing.plugin=Plugin {} already exists, overwriting existing plugin -rendered.prompt=RENDERED PROMPT: \n{} -requested.a.non.existent.service.type.of.consider.requesting.a.textaiservice.instead=Requested a non-existent service type of {}. Consider requesting a TextAIService instead. -something.went.wrong.while.rendering.the.semantic.function.or.while.executing.the.text.completion.function.error=Something went wrong while rendering the semantic function or while executing the text completion. Function: {}.{}. Error: {} -syntax.error.the.template.syntax.used.is.not.valid=Syntax error, the template syntax used is not valid -the.block.type.produced.be.the.tokenizer.was.not.expected=The block type produced be the tokenizer was not expected -the.content.of.the.response.was.invalid=The content of the response was invalid -the.first.arg.of.a.function.must.be.a.quoted.string.variable.or.named.argument=The first arg of a function must be a quoted string, variable or named argument -the.function.is.not.supported=The function is not supported -the.request.timed.out=The request timed out -the.request.was.invalid=The request was invalid -the.request.was.throttled=The request was throttled -the.requested.model.is.not.available=The requested model is not available -the.supplied.configuration.was.invalid=The supplied configuration was invalid -the.template.execution.failed.e.g.a.function.call.threw.an.exception=The template execution failed, e.g. a function call threw an exception -the.template.requires.an.unknown.function=The template requires an unknown function -the.variable.name.contains.invalid.characters.only.alphanumeric.chars.and.underscore.are.allowed=The variable name '{}' contains invalid characters. Only alphanumeric chars and underscore are allowed. -the.variable.name.is.empty=The variable name is empty -there.was.an.error.in.the.service=There was an error in the service -there.was.an.issue.with.the.named.argument.value.for=There was an issue with the named argument value for {} -this.error.indicates.that.you.have.attempted.to.use.a.chat.completion.model=This error indicates that you have attempted to use a chat completion model in a text completion service. Try using a chat completion service instead when building your kernel, for instance when building your service use SKBuilders.chatCompletion() rather than SKBuilders.textCompletionService(). -unable.to.load.prompt.template.config.for.in=Unable to load prompt template config for {} in {} -unable.to.load.service.s=Unable to load service %s -unexpected.named.argument.found.expected.function.name.first=Unexpected named argument found. Expected function name first. -unexpected.second.token.found.0=Unexpected second token found: {0} -unknown.error=Unknown error -variable.not.found=Variable `{}{}` not found \ No newline at end of file diff --git a/semantickernel-api-textembedding-services/pom.xml b/semantickernel-api-textembedding-services/pom.xml deleted file mode 100644 index eb8391355..000000000 --- a/semantickernel-api-textembedding-services/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - Semantic Kernel Services API - Defines the public interface for the Semantic Kernel Services - - - - io.projectreactor - reactor-core - - - com.google.code.findbugs - jsr305 - provided - - - com.github.spotbugs - spotbugs-annotations - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/Embedding.java b/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/Embedding.java deleted file mode 100644 index e98941f6c..000000000 --- a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/Embedding.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.textembedding; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** Represents a strongly typed vector of numeric data. */ -@SuppressFBWarnings("SING_SINGLETON_HAS_NONPRIVATE_CONSTRUCTOR") // This class is not a singleton -public class Embedding { - - // vector is immutable! - private final List vector; - - private static final Embedding EMPTY = new Embedding(); - - /** - * Returns an empty {@code Embedding} instance. - * @return An empty {@code Embedding} instance. - */ - public static Embedding empty() { - return EMPTY; - } - - /** Initializes a new instance of the Embedding class. */ - public Embedding() { - this.vector = Collections.emptyList(); - } - - /** - * Initializes a new instance of the Embedding class that contains numeric elements copied from - * the specified collection - * - * @param vector The collection whose elements are copied to the new Embedding - */ - public Embedding(@Nonnull List vector) { - Objects.requireNonNull(vector); - this.vector = Collections.unmodifiableList(vector); - } - - /** - * Initializes a new instance of the Embedding class that contains numeric elements copied from - * the specified array - * - * @param vector The array whose elements are copied to the new Embedding - */ - public Embedding(@Nonnull float[] vector) { - Objects.requireNonNull(vector); - List list = new ArrayList<>(vector.length); - for (float f : vector) { - list.add(f); - } - this.vector = Collections.unmodifiableList(list); - } - - /** - * Return the embedding vector as a read-only list. - * - * @return The embedding vector as a read-only list. - */ - public List getVector() { - return Collections.unmodifiableList(this.vector); - } -} diff --git a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/EmbeddingGenerationService.java b/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/EmbeddingGenerationService.java deleted file mode 100644 index 561dbe1d7..000000000 --- a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/EmbeddingGenerationService.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.textembedding; - -import com.microsoft.semantickernel.services.AIService; -import java.util.List; -import reactor.core.publisher.Mono; - -/** - * Interface for text embedding generation services - * @param The type of the data to generate embeddings for - */ -public interface EmbeddingGenerationService extends AIService { - - /** - * Generates a list of embeddings associated to the data - * - * @param data List of texts to generate embeddings for - * @return List of embeddings of each data point - */ - Mono> generateEmbeddingsAsync(List data); - - /** - * Generates an embedding associated to the data - * - * @param data Text to generate embedding for - * @return Embedding of the data - */ - - Mono generateEmbeddingAsync(TValue data); - -} diff --git a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/TextEmbeddingGenerationService.java b/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/TextEmbeddingGenerationService.java deleted file mode 100644 index 28c2556a0..000000000 --- a/semantickernel-api-textembedding-services/src/main/java/com/microsoft/semantickernel/services/textembedding/TextEmbeddingGenerationService.java +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.textembedding; - -import com.microsoft.semantickernel.services.AIService; - -/** Interface for text embedding generation services */ -public interface TextEmbeddingGenerationService - extends EmbeddingGenerationService, AIService { -} diff --git a/semantickernel-api/pom.xml b/semantickernel-api/pom.xml deleted file mode 100644 index ace57557c..000000000 --- a/semantickernel-api/pom.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - 4.0.0 - - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - ../pom.xml - - - semantickernel-api - jar - Semantic Kernel API - Defines the public interface for the Semantic Kernel - - - com.microsoft.semantic-kernel - semantickernel-api-data - - - com.microsoft.semantic-kernel - semantickernel-api-exceptions - - - com.microsoft.semantic-kernel - semantickernel-api-builders - - - com.microsoft.semantic-kernel - semantickernel-api-localization - - - com.microsoft.semantic-kernel - semantickernel-api-textembedding-services - - - com.microsoft.semantic-kernel - semantickernel-api-ai-services - - - io.opentelemetry.instrumentation - opentelemetry-reactor-3.1 - 2.9.0-alpha - - - com.azure - azure-ai-openai - - - org.slf4j - slf4j-api - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.jknack - handlebars - - - com.google.code.findbugs - jsr305 - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.apache.commons - commons-text - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.wiremock - wiremock - test - - - - javax.xml.stream - stax-api - provided - - - - org.mockito - mockito-junit-jupiter - test - - - - io.opentelemetry - opentelemetry-api - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack-dependencies - - unpack-dependencies - - - - semantickernel-api-exceptions,semantickernel-api-builders,semantickernel-api-localization,semantickernel-api-textembedding-services,semantickernel-api-ai-services,semantickernel-api-data - - ${project.build.directory}/lib - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 3.6.0 - - - src/assembly/custom.xml - - false - - - - make-assembly - package - - single - - - - - - - diff --git a/semantickernel-api/src/assembly/custom.xml b/semantickernel-api/src/assembly/custom.xml deleted file mode 100644 index 48becfffa..000000000 --- a/semantickernel-api/src/assembly/custom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - with-exceptions - - jar - - false - - - ${project.build.outputDirectory} - / - - - ${project.build.directory}/lib - / - - **/** - - - - \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java deleted file mode 100644 index 5e6cc2fdf..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.orchestration.FunctionInvocation; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.services.AIServiceCollection; -import com.microsoft.semantickernel.services.AIServiceSelection; -import com.microsoft.semantickernel.services.AIServiceSelector; -import com.microsoft.semantickernel.services.OrderedAIServiceSelector; -import com.microsoft.semantickernel.services.ServiceNotFoundException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Provides state for use throughout a Semantic Kernel workload. - *

- * An instance of {@code Kernel} is passed through to every function invocation and service call - * throughout the system, providing to each the ability to access shared state and services. - */ -public class Kernel { - - private final AIServiceSelector serviceSelector; - private final KernelPluginCollection plugins; - private final KernelHooks globalKernelHooks; - - // Only present so we can create a builder in copy method - private final AIServiceCollection services; - - @Nullable - private final Function serviceSelectorProvider; - - /** - * Initializes a new instance of {@code Kernel}. - * - * @param services The collection of services available through the kernel. - * @param serviceSelectorProvider The service selector provider for the kernel. If {@code null}, - * an ordered service selector will be used. - * @param plugins The collection of plugins available through the kernel. If - * {@code null}, an empty collection will be used. - * @param globalKernelHooks The global hooks to be used throughout the kernel. If - * {@code null}, an empty collection will be used. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Kernel( - AIServiceCollection services, - @Nullable Function serviceSelectorProvider, - @Nullable List plugins, - @Nullable KernelHooks globalKernelHooks) { - - this.services = services; - this.serviceSelectorProvider = serviceSelectorProvider; - - AIServiceSelector serviceSelector; - if (serviceSelectorProvider == null) { - serviceSelector = new OrderedAIServiceSelector(services); - } else { - serviceSelector = serviceSelectorProvider.apply(services); - } - this.serviceSelector = serviceSelector; - - if (plugins != null) { - this.plugins = new KernelPluginCollection(plugins); - } else { - this.plugins = new KernelPluginCollection(); - } - - this.globalKernelHooks = new KernelHooks(globalKernelHooks); - } - - /** - * Get the fluent builder for creating a new instance of {@code Kernel}. - * - * @return The fluent builder for creating a new instance of {@code Kernel}. - */ - public static Builder builder() { - return new Kernel.Builder(); - } - - /** - * Creates a Builder that can create a copy of the {@code Kernel}. Use this method if you wish - * to modify the state of the kernel such as adding new plugins or services. - * - * @param kernel The kernel to copy. - * @return A Builder that can create a copy of the instance of {@code Kernel}. - */ - public static Builder from(Kernel kernel) { - return new Builder( - kernel.services, - kernel.serviceSelectorProvider, - kernel.plugins); - } - - /** - * Creates a Builder that can create a copy of the current instance of {@code Kernel}. Use this - * method if you wish to modify the state of the kernel such as adding new plugins or services. - * - * @return A Builder that can create a copy of the current instance of {@code Kernel}. - */ - public Builder toBuilder() { - return new Builder(services, serviceSelectorProvider, plugins); - } - - /** - * Invokes a {@code KernelFunction} function by name. - * - * @param The return type of the function. - * @param pluginName The name of the plugin containing the function. - * @param functionName The name of the function to invoke. - * @return The result of the function invocation. - * @throws IllegalArgumentException if the plugin or function is not found. - * @see KernelFunction#invokeAsync(Kernel) - * @see KernelPluginCollection#getFunction(String, String) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public FunctionInvocation invokeAsync( - String pluginName, - String functionName) { - KernelFunction function = getFunction(pluginName, functionName); - return invokeAsync(function); - } - - /** - * Invokes a {@code KernelFunction} function by name. - * - * @param The return type of the function. - * @param pluginName The name of the plugin containing the function. - * @param functionName The name of the function to invoke. - * @return The result of the function invocation. - * @throws IllegalArgumentException if the plugin or function is not found. - * @see KernelFunction#invokeAsync(Kernel) - * @see KernelPluginCollection#getFunction(String, String) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public FunctionResult invoke( - String pluginName, - String functionName) { - return this.invokeAsync(pluginName, functionName).block(); - } - - /** - * Invokes a Prompt. - * - * @param The return type of the prompt. - * @param prompt The prompt to invoke. - * @return The result of the prompt invocation. - * @see KernelFunction#invokeAsync(Kernel) - */ - public FunctionInvocation invokePromptAsync(@Nonnull String prompt) { - return invokeAsync(KernelFunction.createFromPrompt(prompt).build()); - } - - /** - * Invokes a Prompt. - * - * @param The return type of the prompt. - * @param prompt The prompt to invoke. - * @param arguments The arguments to pass to the prompt. - * @return The result of the prompt invocation. - * @see KernelFunction#invokeAsync(Kernel) - */ - public FunctionInvocation invokePromptAsync(@Nonnull String prompt, - @Nonnull KernelArguments arguments) { - KernelFunction function = KernelFunction.createFromPrompt(prompt).build(); - - return function.invokeAsync(this) - .withArguments(arguments); - } - - /** - * Invokes a Prompt. - * - * @param The return type of the prompt. - * @param prompt The prompt to invoke. - * @param arguments The arguments to pass to the prompt. - * @param invocationContext Additional context to used when invoking the prompt. - * @return The result of the prompt invocation. - * @see KernelFunction#invokeAsync(Kernel) - */ - - public FunctionInvocation invokePromptAsync(@Nonnull String prompt, - @Nonnull KernelArguments arguments, @Nonnull InvocationContext invocationContext) { - - KernelFunction function = KernelFunction.createFromPrompt(prompt).build(); - - return function.invokeAsync(this) - .withArguments(arguments) - .withInvocationContext(invocationContext); - } - - /** - * Invokes a {@code KernelFunction}. - * - * @param The return type of the function. - * @param function The function to invoke. - * @return The result of the function invocation. - * @see KernelFunction#invokeAsync(Kernel) - */ - public FunctionInvocation invokeAsync(KernelFunction function) { - return function.invokeAsync(this); - } - - /** - * Invokes a {@code KernelFunction}. - * - * @param The return type of the function. - * @param function The function to invoke. - * @return The result of the function invocation. - * @see KernelFunction#invokeAsync(Kernel) - */ - public FunctionResult invoke(KernelFunction function) { - return invokeAsync(function).block(); - } - - /** - * Gets the plugin with the specified name. - * - * @param pluginName The name of the plugin to get. - * @return The plugin with the specified name, or {@code null} if no such plugin exists. - */ - @Nullable - public KernelPlugin getPlugin(String pluginName) { - return plugins.getPlugin(pluginName); - } - - /** - * Gets the plugins that were added to the kernel. - * - * @return The plugins available through the kernel (unmodifiable list). - * @see Kernel#getPlugins() - */ - public Collection getPlugins() { - return Collections.unmodifiableCollection(plugins.getPlugins()); - } - - /** - * Gets the function with the specified name from the plugin with the specified name. - * - * @param The return type of the function. - * @param pluginName The name of the plugin containing the function. - * @param functionName The name of the function to get. - * @return The function with the specified name from the plugin with the specified name. - * @throws IllegalArgumentException if the plugin or function is not found. - * @see KernelPluginCollection#getFunction(String, String) - */ - @SuppressWarnings("unchecked") - public KernelFunction getFunction(String pluginName, String functionName) { - return (KernelFunction) plugins.getFunction(pluginName, functionName); - } - - /** - * Gets the functions available through the kernel. Functions are collected from all plugins - * available through the kernel. - * - * @return The functions available through the kernel. - * @see Kernel#getPlugins() - * @see Kernel.Builder#withPlugin(KernelPlugin) - */ - public List> getFunctions() { - return plugins.getFunctions(); - } - - /** - * Get the {@code KernelHooks} used throughout the kernel. These {@code KernelHooks} are used in - * addition to any hooks provided to a function. - * - * @return The {@code KernelHooks} used throughout the kernel. - * @see KernelFunction#invokeAsync(Kernel, KernelArguments, ContextVariableType, - * InvocationContext) - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelHooks getGlobalKernelHooks() { - return globalKernelHooks; - } - - /** - * Get the AIServiceSelector used to query for services available through the kernel. - * - * @return The AIServiceSelector used to query for services available through the kernel. - */ - public AIServiceSelector getServiceSelector() { - return serviceSelector; - } - - /** - * Get the service of the specified type from the kernel. - * - * @param The type of the service to get. - * @param clazz The class of the service to get. - * @return The service of the specified type from the kernel. - * @throws ServiceNotFoundException if the service is not found. - * @see com.microsoft.semantickernel.services.AIServiceSelector#trySelectAIService(Class, KernelArguments) - */ - public T getService(Class clazz) throws ServiceNotFoundException { - AIServiceSelection selector = serviceSelector - .trySelectAIService( - clazz, - null); - - if (selector == null) { - throw new ServiceNotFoundException("Unable to find service of type " + clazz.getName()); - } - - return selector.getService(); - } - - /** - * Get the service of the specified type from the kernel. - * - * @param The type of the service to get. - * @param clazz The class of the service to get. - * @param args The arguments to help select the service to get. - * @return The service of the specified type from the kernel. - * @throws ServiceNotFoundException if the service is not found. - * @see com.microsoft.semantickernel.services.AIServiceSelector#trySelectAIService(Class, KernelArguments) - */ - public T getService(Class clazz, KernelArguments args) - throws ServiceNotFoundException { - AIServiceSelection selector = serviceSelector - .trySelectAIService( - clazz, - args); - - if (selector == null) { - throw new ServiceNotFoundException("Unable to find service of type " + clazz.getName()); - } - - return selector.getService(); - } - - /** - * A fluent builder for creating a new instance of {@code Kernel}. - */ - public static class Builder implements SemanticKernelBuilder { - - private final AIServiceCollection services = new AIServiceCollection(); - private final List plugins = new ArrayList<>(); - @Nullable - private Function serviceSelectorProvider; - - /** - * Construct a Builder for creating a new instance of {@code Kernel}. - */ - public Builder() { - } - - private Builder( - AIServiceCollection services, - @Nullable Function serviceSelectorProvider, - KernelPluginCollection plugins) { - this.services.putAll(services); - this.serviceSelectorProvider = serviceSelectorProvider; - this.plugins.addAll(plugins.getPlugins()); - } - - /** - * Adds a service to the kernel. - * - * @param The type of the service to add. - * @param clazz The class of the service to add. - * @param aiService The service to add. - * @return {@code this} builder with the service added. - */ - public Builder withAIService(Class clazz, T aiService) { - services.put(clazz, aiService); - return this; - } - - /** - * Adds a plugin to the kernel. - * - * @param plugin The plugin to add. - * @return {@code this} builder with the plugin added. - */ - public Kernel.Builder withPlugin(KernelPlugin plugin) { - plugins.add(plugin); - return this; - } - - /** - * Sets the service selector provider for the kernel. - * - * @param serviceSelector The service selector provider for the kernel. - * @return {@code this} builder with the service selector provider set. - */ - public Kernel.Builder withServiceSelector( - Function serviceSelector) { - this.serviceSelectorProvider = serviceSelector; - return this; - } - - /** - * Builds a new instance of {@code Kernel} with the services and plugins provided. - * - * @return A new instance of {@code Kernel}. - */ - @Override - public Kernel build() { - return new Kernel( - services, - serviceSelectorProvider, - plugins, - null); - } - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelPluginCollection.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelPluginCollection.java deleted file mode 100644 index 12d4e50ad..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelPluginCollection.java +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel; - -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A collection of {@link KernelPlugin} instances. - */ -class KernelPluginCollection { - - private static final Logger LOGGER = LoggerFactory.getLogger(KernelPluginCollection.class); - - private final Map plugins = new CaseInsensitiveMap<>(); - - /** - * Initialize a new instance of the {@link KernelPluginCollection} class with an empty - * collection of plugins. - */ - KernelPluginCollection() { - } - - /** - * Initialize a new instance of the {@link KernelPluginCollection} class from a collection of - * plugins. - */ - KernelPluginCollection(List plugins) { - plugins.forEach(plugin -> putOrMerge(plugin.getName(), plugin)); - } - - private void putOrMerge(String pluginName, KernelPlugin plugin) { - if (plugins.containsKey(pluginName)) { - plugin.getFunctions() - .entrySet() - .forEach(entry -> plugins.get(pluginName).addFunction(entry.getValue())); - } else { - plugins.put(pluginName, plugin); - } - } - - /** - * Gets the function with the given name from the plugin with the given name. - * - * @param pluginName The name of the plugin containing the function. - * @param functionName The name of the function to get. - * @return The function with the given name from the plugin with the given name. - * @throws IllegalArgumentException If the plugin or function is not found. - */ - KernelFunction getFunction(String pluginName, String functionName) { - KernelPlugin plugin = plugins.get(pluginName); - if (plugin == null) { - throw new SKException("Failed to find plugin " + pluginName); - } - KernelFunction function = plugin.get(functionName); - - if (function == null) { - throw new SKException( - "Function '" + functionName + "' not found in plugin '" + pluginName + "'"); - } - return function; - } - - /** - * Gets all functions from all plugins. - * - * @return A list of all functions from all plugins. - */ - List> getFunctions() { - return plugins.values().stream() - .flatMap(plugin -> plugin.getFunctions().values().stream()) - .collect(Collectors.toList()); - } - - /** - * Gets all function metadata from all plugins. - * - * @return A list of all function metadata from all plugins. - */ - List> getFunctionsMetadata() { - return plugins.values().stream() - .flatMap(plugin -> plugin.getFunctions().values().stream()) - .map(KernelFunction::getMetadata) - .collect(Collectors.toList()); - } - - /** - * Gets all plugins that were added to the kernel. - * - * @return The plugins available through the kernel. - */ - Collection getPlugins() { - return Collections.unmodifiableCollection(plugins.values()); - } - - /** - * Gets the plugin with the specified name. - * - * @param pluginName The name of the plugin to get. - * @return The plugin with the specified name, or {@code null} if no such plugin exists. - */ - @Nullable - KernelPlugin getPlugin(String pluginName) { - return plugins.get(pluginName); - } - - /** - * Adds a plugin to the collection. If a plugin with the same name already exists, it will be - * replaced. - * - * @param plugin The plugin to add. - */ - void add(KernelPlugin plugin) { - if (plugins.containsKey(plugin.getName())) { - LOGGER.warn(SemanticKernelResources.getString( - "plugin.already.exists.overwriting.existing.plugin"), plugin.getName()); - } - - plugins.put(plugin.getName(), plugin); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java deleted file mode 100644 index f69b2152d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/Agent.java +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; -import java.util.function.Supplier; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import javax.annotation.Nullable; - -/** - * Interface for a semantic kernel agent. - */ -public interface Agent { - - /** - * Gets the agent's ID. - * - * @return The agent's ID - */ - String getId(); - - /** - * Gets the agent's name. - * - * @return The agent's name - */ - String getName(); - - /** - * Gets the agent's description. - * - * @return The agent's description - */ - String getDescription(); - - /** - * Invokes the agent with the given message. - * - * @param message The message to process - * @return A Mono containing the agent response - */ - Mono>>> invokeAsync( - @Nullable ChatMessageContent message); - - /** - * Invokes the agent with the given message and thread. - * - * @param message The message to process - * @param thread The agent thread to use - * @return A Mono containing the agent response - */ - Mono>>> invokeAsync( - @Nullable ChatMessageContent message, - @Nullable AgentThread thread); - - /** - * Invokes the agent with the given message, thread, and options. - * - * @param message The message to process - * @param thread The agent thread to use - * @param options The options for invoking the agent - * @return A Mono containing the agent response - */ - Mono>>> invokeAsync( - @Nullable ChatMessageContent message, - @Nullable AgentThread thread, - @Nullable AgentInvokeOptions options); - - /** - * Invoke the agent with the given chat history. - * - * @param messages The chat history to process - * @param thread The agent thread to use - * @param options The options for invoking the agent - * @return A Mono containing the agent response - */ - Mono>>> invokeAsync( - List> messages, - @Nullable AgentThread thread, - @Nullable AgentInvokeOptions options); - - /** - * Notifies the agent of a new message. - * - * @param thread The agent thread to use - */ - Mono notifyThreadOfNewMessageAsync(AgentThread thread, ChatMessageContent newMessage); -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java deleted file mode 100644 index 6b6d57ed3..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentInvokeOptions.java +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nullable; - -/** - * Options for invoking an agent. - */ -public class AgentInvokeOptions { - - @Nullable - private final KernelArguments kernelArguments; - @Nullable - private final Kernel kernel; - @Nullable - private final String additionalInstructions; - @Nullable - private final InvocationContext invocationContext; - - /** - * Default constructor for AgentInvokeOptions. - */ - public AgentInvokeOptions() { - this(null, null, null, null); - } - - /** - * Constructor for AgentInvokeOptions. - * - * @param kernelArguments The arguments for the kernel function. - * @param kernel The kernel to use. - * @param additionalInstructions Additional instructions for the agent. - * @param invocationContext The invocation context. - */ - public AgentInvokeOptions(@Nullable KernelArguments kernelArguments, - @Nullable Kernel kernel, - @Nullable String additionalInstructions, - @Nullable InvocationContext invocationContext) { - this.kernelArguments = kernelArguments != null ? kernelArguments.copy() : null; - this.kernel = kernel; - this.additionalInstructions = additionalInstructions; - this.invocationContext = invocationContext; - } - - /** - * Get the kernel arguments. - * - * @return The kernel arguments. - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelArguments getKernelArguments() { - return kernelArguments; - } - - /** - * Get the kernel. - * - * @return The kernel. - */ - public Kernel getKernel() { - return kernel; - } - - /** - * Get additional instructions. - * - * @return The additional instructions. - */ - public String getAdditionalInstructions() { - return additionalInstructions; - } - - /** - * Get the invocation context. - * - * @return The invocation context. - */ - public InvocationContext getInvocationContext() { - return invocationContext; - } - - /** - * Builder for AgentInvokeOptions. - */ - public static Builder builder() { - return new Builder(); - } - - public static class Builder implements SemanticKernelBuilder { - - private KernelArguments kernelArguments; - private Kernel kernel; - private String additionalInstructions; - private InvocationContext invocationContext; - - /** - * Set the kernel arguments. - * - * @param kernelArguments The kernel arguments. - * @return The builder. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withKernelArguments(KernelArguments kernelArguments) { - this.kernelArguments = kernelArguments; - return this; - } - - /** - * Set the kernel. - * - * @param kernel The kernel. - * @return The builder. - */ - public Builder withKernel(Kernel kernel) { - this.kernel = kernel; - return this; - } - - /** - * Set additional instructions. - * - * @param additionalInstructions The additional instructions. - * @return The builder. - */ - public Builder withAdditionalInstructions(String additionalInstructions) { - this.additionalInstructions = additionalInstructions; - return this; - } - - /** - * Set the invocation context. - * - * @param invocationContext The invocation context. - * @return The builder. - */ - public Builder withInvocationContext(InvocationContext invocationContext) { - this.invocationContext = invocationContext; - return this; - } - - /** - * Build the object. - * - * @return a constructed object. - */ - @Override - public AgentInvokeOptions build() { - return new AgentInvokeOptions( - kernelArguments, - kernel, - additionalInstructions, - invocationContext); - } - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java deleted file mode 100644 index 0b4550986..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentResponseItem.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -public class AgentResponseItem { - private final T message; - private final AgentThread thread; - - @SuppressFBWarnings("EI_EXPOSE_REP2") - public AgentResponseItem(T message, AgentThread thread) { - this.message = message; - this.thread = thread; - } - - /** - * Gets the agent response message. - * - * @return The message. - */ - public T getMessage() { - return message; - } - - /** - * Gets the thread. - * - * @return The thread. - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public AgentThread getThread() { - return thread; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java deleted file mode 100644 index 94538f41a..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/AgentThread.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import reactor.core.publisher.Mono; - -/** - * Interface for an agent thread. - */ -public interface AgentThread { - /** - * Get the thread ID. - * - * @return The thread ID. - */ - String getId(); - - /** - * Create a new thread. - * - * @return A Mono containing the thread ID. - */ - Mono createAsync(); - - /** - * Delete the thread. - * - * @return A Mono indicating completion. - */ - Mono deleteAsync(); - - /** - * Check if the thread is deleted. - * - * @return A Mono containing true if the thread is deleted, false otherwise. - */ - boolean isDeleted(); - - /** - * Create a copy of the thread. - * - * @return A new instance of the thread. - */ - AgentThread copy(); - - /** - * Handle a new message in the thread. - * - * @param newMessage The new message to handle. - * @return A Mono indicating completion. - */ - Mono onNewMessageAsync(ChatMessageContent newMessage); -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java deleted file mode 100644 index c66fe9b90..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/BaseAgentThread.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -public abstract class BaseAgentThread implements AgentThread { - - protected String id; - protected boolean isDeleted; - - public BaseAgentThread() { - } - - public BaseAgentThread(String id) { - this.id = id; - } - - @Override - public String getId() { - return id; - } - - @Override - public boolean isDeleted() { - return isDeleted; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java deleted file mode 100644 index 8403093eb..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/agents/KernelAgent.java +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.agents; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.InvocationReturnMode; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Supplier; - -public abstract class KernelAgent implements Agent { - - protected final String id; - protected final String name; - protected final String description; - protected final Kernel kernel; - protected final KernelArguments kernelArguments; - protected final InvocationContext invocationContext; - protected final String instructions; - protected final PromptTemplate template; - - protected KernelAgent( - String id, - String name, - String description, - Kernel kernel, - KernelArguments kernelArguments, - InvocationContext invocationContext, - String instructions, - PromptTemplate template) { - this.id = id != null ? id : UUID.randomUUID().toString(); - this.name = name; - this.description = description; - this.kernel = kernel; - this.kernelArguments = kernelArguments != null - ? kernelArguments.copy() - : KernelArguments.builder().build(); - this.invocationContext = invocationContext != null - ? invocationContext - : InvocationContext.builder().build(); - this.instructions = instructions; - this.template = template; - } - - /** - * Gets the agent's ID. - * - * @return The agent's ID - */ - public String getId() { - return id; - } - - /** - * Gets the agent's name. - * - * @return The agent's name - */ - public String getName() { - return name; - } - - /** - * Gets the agent's description. - * - * @return The agent's description - */ - public String getDescription() { - return description; - } - - /** - * Gets the kernel used by the agent. - * - * @return The kernel used by the agent - */ - public Kernel getKernel() { - return kernel; - } - - /** - * Gets the invocation context used by the agent. - * - * @return The invocation context used by the agent - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelArguments getKernelArguments() { - return kernelArguments; - } - - /** - * Gets the invocation context used by the agent. - * - * @return The invocation context used by the agent - */ - public String getInstructions() { - return instructions; - } - - /** - * Gets the invocation context used by the agent. - * - * @return The invocation context used by the agent - */ - public PromptTemplate getTemplate() { - return template; - } - - /** - * Merges the provided arguments with the current arguments. - * Provided arguments will override the current arguments. - * - * @param arguments The arguments to merge with the current arguments. - */ - protected KernelArguments mergeArguments(KernelArguments arguments) { - if (arguments == null) { - return kernelArguments; - } - - Map executionSettings = new HashMap<>( - kernelArguments.getExecutionSettings()); - executionSettings.putAll(arguments.getExecutionSettings()); - - return KernelArguments.builder() - .withVariables(kernelArguments) - .withVariables(arguments) - .withExecutionSettings(executionSettings) - .build(); - } - - /** - * Formats the instructions using the provided kernel, arguments, and context. - * - * @param kernel The kernel to use for formatting. - * @param arguments The arguments to use for formatting. - * @param context The context to use for formatting. - * @return A Mono that resolves to the formatted instructions. - */ - protected Mono renderInstructionsAsync(Kernel kernel, KernelArguments arguments, - InvocationContext context) { - if (template != null) { - return template.renderAsync(kernel, arguments, context); - } else { - return Mono.just(instructions); - } - } - - protected Mono ensureThreadExistsWithMessagesAsync( - List> messages, AgentThread thread, Supplier threadSupplier) { - return Mono.defer(() -> { - // Check if the thread already exists - // If it does, we can work with a copy of it - AgentThread newThread = thread == null ? threadSupplier.get() : thread.copy(); - - return newThread.createAsync() - .thenMany(Flux.fromIterable(messages)) - .concatMap(message -> { - return notifyThreadOfNewMessageAsync(newThread, message) - .then(Mono.just(message)); - }) - .then(Mono.just((T) newThread)); - }); - } - - @Override - public Mono>>> invokeAsync( - @Nullable ChatMessageContent message) { - return invokeAsync(message, null, null); - } - - @Override - public Mono>>> invokeAsync( - @Nullable ChatMessageContent message, - @Nullable AgentThread thread) { - return invokeAsync(message, thread, null); - } - - @Override - public Mono>>> invokeAsync( - @Nullable ChatMessageContent message, - @Nullable AgentThread thread, - @Nullable AgentInvokeOptions options) { - ArrayList> messages = new ArrayList<>(); - if (message != null) { - messages.add(message); - } - return invokeAsync(messages, thread, options); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/connectors/WebSearchEngineConnector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/connectors/WebSearchEngineConnector.java deleted file mode 100644 index 0d1bf8777..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/connectors/WebSearchEngineConnector.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.connectors; - -import java.util.List; -import reactor.core.publisher.Mono; - -/** - * Web search engine connector interface. - */ -public interface WebSearchEngineConnector { - - /** - * Execute a web search engine search. - * - * @param query Query to search. - * @param count Number of results. Defaults to 1. Must be between 1 and 50. - * @param offset Number of results to skip. Defaults to 0. - * @return First snippet returned from search. - */ - Mono> searchAsync(String query, int count, int offset); - - /** - * Represents a web page. - */ - interface WebPage { - - /** - * Gets the name of the web page. - * - * @return The name of the web page. - */ - String getName(); - - /** - * Gets the URL of the web page. - * - * @return The URL of the web page. - */ - String getUrl(); - - /** - * Gets the snippet of the web page. - * - * @return The snippet of the web page. - */ - String getSnippet(); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contents/FunctionCallContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contents/FunctionCallContent.java deleted file mode 100644 index 8c973ab01..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contents/FunctionCallContent.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contents; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.KernelContentImpl; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Represents the content of a function call. - *

- * This class is used to represent a function call in the context of a chat message. - */ -public class FunctionCallContent extends KernelContentImpl { - - @Nullable - private final String id; - @Nullable - private final String pluginName; - private final String functionName; - @Nullable - private final KernelArguments arguments; - - /** - * Creates a new instance of the {@link FunctionCallContent} class. - * - * @param functionName The name of the function. - * @param pluginName The name of the plugin with which this function is associated, if any. - * @param id The ID of the tool call. - * @param arguments A name/value collection of the arguments to the function, if any. - */ - public FunctionCallContent( - String functionName, - @Nullable String pluginName, - @Nullable String id, - @Nullable KernelArguments arguments) { - this.functionName = functionName; - this.pluginName = pluginName; - this.id = id; - if (arguments == null) { - this.arguments = null; - } else { - this.arguments = arguments.copy(); - } - } - - /** - * Gets the ID of the tool call. - * - * @return The ID of the tool call. - */ - @Nullable - public String getId() { - return id; - } - - /** - * Gets the name of the plugin with which this function is associated, if any. - * - * @return The name of the plugin with which this function is associated, if any. - */ - @Nullable - public String getPluginName() { - return pluginName; - } - - /** - * Gets the name of the function. - * - * @return The name of the function. - */ - public String getFunctionName() { - return functionName; - } - - /** - * Gets a name/value collection of the arguments to the function, if any. - * - * @return A name/value collection of the arguments to the function, if any. - */ - @Nullable - public KernelArguments getArguments() { - if (arguments == null) { - return null; - } - return arguments.copy(); - } - - /** - * Gets list of function calls from the message content. - * - * @param messageContent The message content. - * @return The function calls. - */ - public static List getFunctionCalls(ChatMessageContent messageContent) { - if (messageContent.getItems() == null) { - return null; - } - - return messageContent.getItems().stream().filter( - item -> item instanceof FunctionCallContent) - .map(item -> (FunctionCallContent) item) - .collect(Collectors.toList()); - } - - /** - * Gets the content returned by the AI service. - * - * @return The content. - */ - @Nullable - @Override - public String getContent() { - return null; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/CaseInsensitiveMap.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/CaseInsensitiveMap.java deleted file mode 100644 index daf78791c..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/CaseInsensitiveMap.java +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -/** - * A {@code java.util.HashMap} in which the keys are case-insensitive. - * - * @param the type of the value - */ -public class CaseInsensitiveMap extends HashMap { - - /** - * Creates a new instance of the {@link CaseInsensitiveMap} class. - * - * @param kvMap the map - */ - public CaseInsensitiveMap(Map kvMap) { - super(); - putAll(kvMap); - } - - /** - * Creates a new instance of the {@link CaseInsensitiveMap} class. - */ - public CaseInsensitiveMap() { - super(); - } - - @Override - public T computeIfAbsent(String key, Function mappingFunction) { - if (key == null) { - return super.computeIfAbsent(null, mappingFunction); - } - return super.computeIfAbsent(key.toLowerCase(Locale.ROOT), mappingFunction); - } - - @Override - public T computeIfPresent( - String key, BiFunction remappingFunction) { - if (key == null) { - return super.computeIfPresent(null, remappingFunction); - } - return super.computeIfPresent(key.toLowerCase(Locale.ROOT), remappingFunction); - } - - @Override - public T compute( - String key, BiFunction remappingFunction) { - if (key == null) { - return super.compute(null, remappingFunction); - } - return super.compute(key.toLowerCase(Locale.ROOT), remappingFunction); - } - - @Override - public boolean containsKey(Object key) { - if (key == null) { - return super.containsKey(null); - } - return super.containsKey(((String) key).toLowerCase(Locale.ROOT)); - } - - @Nullable - @Override - public T get(Object key) { - if (key == null) { - return super.get(null); - } - return super.get(((String) key).toLowerCase(Locale.ROOT)); - } - - @Override - public T getOrDefault(Object key, T defaultValue) { - if (key == null) { - return super.getOrDefault(null, defaultValue); - } - return super.getOrDefault(((String) key).toLowerCase(Locale.ROOT), defaultValue); - } - - @Override - public T merge( - String key, T value, BiFunction remappingFunction) { - if (key == null) { - return super.merge(null, value, remappingFunction); - } - return super.merge(key.toLowerCase(Locale.ROOT), value, remappingFunction); - } - - @Override - public T put(String key, T value) { - if (key == null) { - return super.put(null, value); - } - return super.put(key.toLowerCase(Locale.ROOT), value); - } - - @Override - public void putAll(Map m) { - super.putAll( - m.entrySet().stream() - .collect( - Collectors.toMap( - key -> key.getKey().toLowerCase(Locale.ROOT), - Entry::getValue))); - } - - @Override - public T putIfAbsent(String key, T value) { - if (key == null) { - return super.putIfAbsent(null, value); - } - return super.putIfAbsent(key.toLowerCase(Locale.ROOT), value); - } - - @Override - public boolean remove(Object key, Object value) { - if (key == null) { - return super.remove(null, value); - } - return super.remove(((String) key).toLowerCase(Locale.ROOT), value); - } - - @Override - public T remove(Object key) { - if (key == null) { - return super.remove(null); - } - return super.remove(((String) key).toLowerCase(Locale.ROOT)); - } - - @Override - public boolean replace(String key, T oldValue, T newValue) { - - if (key == null) { - return super.replace(null, oldValue, newValue); - } - return super.replace(key.toLowerCase(Locale.ROOT), oldValue, newValue); - } - - @Override - public T replace(String key, T value) { - if (key == null) { - return super.replace(null, value); - } - return super.replace(key.toLowerCase(Locale.ROOT), value); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariable.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariable.java deleted file mode 100644 index 5e79b872d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariable.java +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables; - -import com.azure.ai.openai.models.CompletionsUsage; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter.NoopConverter; -import com.microsoft.semantickernel.exceptions.SKException; -import java.time.OffsetDateTime; -import java.util.Collections; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * A context variable wraps an arbitrary value and a {@code ContextVariableType}. - * {@code ContextVariableType} is used throughout the Semantic Kernel for passing arguments to - * functions and as function return types. - * - * @param the type of the context variable - */ -public class ContextVariable { - - private final ContextVariableType type; - - @Nullable - private final T value; - - /** - * Creates a new instance of the {@link ContextVariable} class. - * - * @param type the type - * @param value the value - */ - public ContextVariable( - ContextVariableType type, - @Nullable T value) { - this.type = type; - this.value = value; - } - - /** - * Converts the given value to the requested result type. - * - * @param the type of the requested result - * @param the type of the input value - * @param it the input value - * @param requestedResultType the requested result type - * @return the converted value - */ - public static ContextVariable convert( - @Nullable U it, - ContextVariableType requestedResultType) { - return convert( - it, - requestedResultType.getClazz(), - new ContextVariableTypes( - Collections.singletonList(requestedResultType.getConverter()))); - } - - /** - * Converts the given value to the requested result type. The {@code ContextVariableTypes} - * parameter is used to find the appropriate converter for the input value and the requested - * result type. - * - * @param the type of the requested result - * @param the type of the input value - * @param it the input value - * @param requestedResultType the requested result type - * @param contextVariableTypes the context variable types - * @return the converted value - * @throws SKException if a type converter cannot be found, or the input value cannot be - * converted to the requested result type - */ - public static ContextVariable convert( - @Nullable U it, - Class requestedResultType, - @Nullable ContextVariableTypes contextVariableTypes) { - if (contextVariableTypes == null) { - contextVariableTypes = new ContextVariableTypes(); - } - - if (it instanceof ContextVariable) { - it = (U) ((ContextVariable) it).getValue(); - } - - if (it == null) { - return new ContextVariable<>( - contextVariableTypes.getVariableTypeForClass(requestedResultType), - null); - } - - if (requestedResultType.isAssignableFrom(it.getClass())) { - try { - return contextVariableTypes - .getVariableTypeForClass(requestedResultType) - .of(requestedResultType.cast(it)); - } catch (Exception e) { - return new ContextVariable<>( - new ContextVariableType<>( - new NoopConverter<>(requestedResultType), - requestedResultType), - requestedResultType.cast(it)); - } - } - - ContextVariableType requestedResultTypeVariable; - - try { - requestedResultTypeVariable = contextVariableTypes.getVariableTypeForClass( - requestedResultType); - } catch (Exception e) { - throw new SKException("Unable to find variable type for " + requestedResultType, e); - } - - ContextVariableType typeOfActualReturnedType = null; - - try { - // First try to convert from type ? to T using the converter of ? and see if it can convert it to T. - typeOfActualReturnedType = contextVariableTypes - .getVariableTypeForClass((Class) it.getClass()); - } catch (Exception e) { - try { - typeOfActualReturnedType = contextVariableTypes - .getVariableTypeForSuperClass((Class) it.getClass()); - } catch (Exception e2) { - // ignore - } - } - - if (typeOfActualReturnedType != null) { - // Try the to object - T converted = typeOfActualReturnedType.getConverter().toObject(contextVariableTypes, it, - requestedResultType, false); - - if (converted != null) { - return contextVariableTypes.getVariableTypeForClass(requestedResultType) - .of(converted); - } - - if (requestedResultType.isAssignableFrom(String.class)) { - // Try using toPromptString - String str = typeOfActualReturnedType.getConverter() - .toPromptString( - contextVariableTypes, - typeOfActualReturnedType.getClazz().cast(it)); - - return requestedResultTypeVariable.of(str); - } - } - - // Try getting a converter of type T and see if it can convert ? to T. - if (requestedResultTypeVariable != null) { - // Try using from object - T result = requestedResultTypeVariable.getConverter().fromObject(it); - if (result != null) { - return requestedResultTypeVariable.of(result); - } - - if (it.getClass().equals(String.class)) { - // Try using from prompt string - return requestedResultTypeVariable.of( - requestedResultTypeVariable.getConverter().fromPromptString((String) it)); - } - } - - throw new SKException("Unable to convert " + it.getClass() + " to " + requestedResultType); - } - - /** - * Creates a new instance of the {@link ContextVariable} class without using strong typing. - * - * @param value the value - * @param clazz the class - * @param types the types - * @return the new instance - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static ContextVariable untypedOf( - @Nullable Object value, - Class clazz, - ContextVariableTypes types) { - ContextVariableType type = types.getVariableTypeForClass(clazz); - - return new ContextVariable(type, value); - } - - /** - * Convenience method for creating a {@code ContextVariable} from the given - * {@code CompletionsUsage} instance. - * - * @param x the value - * @return the new instance - */ - public static ContextVariable of(CompletionsUsage x) { - return ofValue(x); - } - - /** - * Convenience method for creating a {@code ContextVariable} from the given - * {@code OffsetDateTime} instance. - * - * @param x the value - * @return the new instance - */ - public static ContextVariable of(OffsetDateTime x) { - return ofValue(x); - } - - /** - * Convenience method for creating a {@code ContextVariable} from the given {@code String} - * instance. - * - * @param value the value - * @return the new instance - */ - public static ContextVariable of(String value) { - return ofValue(value); - } - - /** - * Convenience method for creating a {@code ContextVariable} from the given object. - * - * @param x the object - * @return the new instance - */ - public static ContextVariable ofGlobalType(Object x) { - return ofValue(x); - } - - @SuppressWarnings("unchecked") - private static ContextVariable ofValue(T value) { - Objects.requireNonNull(value, "value cannot be null"); - - if (value instanceof ContextVariable) { - return (ContextVariable) value; - } - - ContextVariableType type = ContextVariableTypes.getGlobalVariableTypeForClass( - (Class) value.getClass()); - return new ContextVariable<>(type, value); - } - - /** - * Creates a new instance of the {@link ContextVariable} class. - * - * @param value the value - * @param converter the converter - * @param the type of the value - * @return the new instance - */ - public static ContextVariable of(T value, ContextVariableTypeConverter converter) { - Objects.requireNonNull(value, "value cannot be null"); - Objects.requireNonNull(converter, "converter cannot be null"); - ContextVariableType type = new ContextVariableType<>(converter, converter.getType()); - return new ContextVariable<>(type, value); - } - - /** - * Get the value of the context variable. - * - * @return the value - */ - @Nullable - public T getValue() { - return value; - } - - /** - * Get the value of the context variable. - * - * @param clazz the class - * @param the type of the value - * @return the value - * @throws SKException if the value cannot be cast to the requested type - */ - @Nullable - public U getValue(Class clazz) { - try { - return clazz.cast(value); - } catch (ClassCastException e) { - throw new SKException( - "Cannot cast " + (value != null ? value.getClass() : "null") + " to " + clazz, e); - } - } - - /** - * Get the type of the context variable. - * - * @return the type - */ - public ContextVariableType getType() { - return type; - } - - /** - * Use the given {@code ContextVariableTypeConverter} to convert the value of this - * {@code ContextVariable} to a prompt string. This method is useful when the convert of this - * {@code ContextVariableType} does not create the expected prompt string. - * - * @param types the types to use when converting the value, if {@code null} the global types - * are used - * @param converter the converter to use when converting the value - * @return the value of this {@code ContextVariable} as a prompt string - */ - public String toPromptString( - @Nullable ContextVariableTypes types, - ContextVariableTypeConverter converter) { - return converter.toPromptString(types, value); - } - - /** - * Use the given {@code ContextVariableTypeConverter} to convert the value of this - * {@code ContextVariable} to a prompt string. This method is useful when the convert of this - * {@code ContextVariableType} does not create the expected prompt string. - * - * @param types the types to use when converting the value - * @return the value of this {@code ContextVariable} as a prompt string - */ - public String toPromptString(ContextVariableTypes types) { - return toPromptString(types, type.getConverter()); - } - - /** - * Use the given {@code ContextVariableTypeConverter} to convert the value of this - * {@code ContextVariable} to a prompt string. This method is useful when the convert of this - * {@code ContextVariableType} does not create the expected prompt string. - * - * @return the value of this {@code ContextVariable} as a prompt string - */ - public String toPromptString() { - return toPromptString(null, type.getConverter()); - } - - /** - * Returns true if the value of this {@code ContextVariable} is {@code null} or empty. - * - * @return true if the value is {@code null} or empty - */ - public boolean isEmpty() { - return value == null || value.toString().isEmpty(); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableType.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableType.java deleted file mode 100644 index 523361e23..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableType.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables; - -import javax.annotation.Nullable; - -/** - * A type of context variable, with a converter to convert objects to the type. - * - * @param The type of the context variable. - */ -public class ContextVariableType { - - private final ContextVariableTypeConverter contextVariableTypeConverter; - private final Class clazz; - - /** - * Create a new context variable type. - * - * @param contextVariableTypeConverter The converter to convert objects to the type. - * @param clazz The class of the type - */ - public ContextVariableType(ContextVariableTypeConverter contextVariableTypeConverter, - Class clazz) { - this.contextVariableTypeConverter = contextVariableTypeConverter; - this.clazz = clazz; - } - - /** - * Get the converter for this type. - * - * @return The converter for this type. - */ - public ContextVariableTypeConverter getConverter() { - return contextVariableTypeConverter; - } - - /** - * Get the class of the type. - * - * @return The class of the type. - */ - public Class getClazz() { - return clazz; - } - - /** - * Create a context variable of this type from the given object, converting it to type T if - * necessary. - * - * @param it The object to convert. - * @return A context variable of this type. - */ - public ContextVariable of(@Nullable Object it) { - if (it == null) { - return new ContextVariable<>( - this, - clazz.cast(null)); - } - - if (clazz.isAssignableFrom(it.getClass())) { - return ContextVariable.of(clazz.cast(it), getConverter()); - } - ContextVariableTypeConverter converter = getConverter(); - - return new ContextVariable<>( - this, - converter.fromObject(it)); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java deleted file mode 100644 index 22d53ec06..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A converter for a context variable type. This class is used to convert objects to and from a - * prompt string, and to convert objects to the type of the context variable. - * - * @param the type of the context variable - */ -public class ContextVariableTypeConverter { - - private static final Logger LOGGER = LoggerFactory.getLogger( - ContextVariableTypeConverter.class); - - /** - * A function to convert ContextVariable to a prompt string. - * @param the type of ContextVariable to convert - */ - public interface ToPromptStringFunction { - - /** - * Convert the type to a prompt string. - * - * @param types the context variable types - * @param t the type to convert - * @return the prompt string - */ - String toPromptString(ContextVariableTypes types, T t); - } - - private final Class clazz; - private final Function fromObject; - private final ToPromptStringFunction toPromptString; - private final Function fromPromptString; - private final List> toObjects; - - /** - * Create a new context variable type converter. - * - * @param clazz the class of the type - * @param fromObject a function to convert an object to the type - * @param toPromptString a function to convert the type to a prompt string - * @param fromPromptString a function to convert a prompt string to the type - */ - public ContextVariableTypeConverter( - Class clazz, - Function fromObject, - Function toPromptString, - Function fromPromptString) { - this(clazz, fromObject, toPromptString, fromPromptString, Collections.emptyList()); - } - - /** - * Create a new context variable type converter. - * - * @param clazz the class of the type - * @param fromObject a function to convert an object to the type - * @param toPromptString a function to convert the type to a prompt string - * @param fromPromptString a function to convert a prompt string to the type - */ - public ContextVariableTypeConverter( - Class clazz, - Function fromObject, - ToPromptStringFunction toPromptString, - Function fromPromptString) { - this(clazz, fromObject, toPromptString, fromPromptString, Collections.emptyList()); - } - - /** - * Create a new context variable type converter. - * - * @param clazz the class of the type - * @param fromObject a function to convert an object to the type - * @param toPromptString a function to convert the type to a prompt string - * @param fromPromptString a function to convert a prompt string to the type - * @param toObjects a list of converters to convert the type to other types - */ - public ContextVariableTypeConverter( - Class clazz, - Function fromObject, - ToPromptStringFunction toPromptString, - Function fromPromptString, - List> toObjects) { - this.clazz = clazz; - this.fromObject = fromObject; - this.toPromptString = toPromptString; - this.fromPromptString = fromPromptString; - this.toObjects = new ArrayList<>(toObjects); - } - - /** - * Create a new context variable type converter. - * - * @param clazz the class of the type - * @param fromObject a function to convert an object to the type - * @param toPromptString a function to convert the type to a prompt string - * @param fromPromptString a function to convert a prompt string to the type - * @param toObjects a list of converters to convert the type to other types - */ - public ContextVariableTypeConverter( - Class clazz, - Function fromObject, - Function toPromptString, - Function fromPromptString, - List> toObjects) { - this.clazz = clazz; - this.fromObject = fromObject; - this.toPromptString = (types, t) -> toPromptString.apply(t); - this.fromPromptString = fromPromptString; - this.toObjects = new ArrayList<>(toObjects); - } - - /** - * Use this converter to convert the object to the type of the context variable. - * - * @param the type to convert to - * @param types the context variable types - * @param t the object to convert - * @param clazz the class of the type to convert to - * @return the converted object - */ - @Nullable - @SuppressWarnings("unchecked") - public U toObject(ContextVariableTypes types, @Nullable Object t, Class clazz) { - return toObject(types, t, clazz, true); - } - - /** - * Use this converter to convert the object to the type of the context variable. - * - * @param types the context variable types - * @param t the object to convert - * @param clazz the class of the type to convert to - * @param logWarnings whether to log warnings - * @param the type to convert to - * @return the converted object - */ - @Nullable - @SuppressWarnings("unchecked") - public U toObject(ContextVariableTypes types, @Nullable Object t, Class clazz, - boolean logWarnings) { - if (t == null) { - return null; - } - - Optional> converter = toObjects - .stream() - .filter(c -> c.getTargetType().equals(clazz)) - .findFirst(); - - if (converter.isPresent()) { - return (U) converter.get().toObject((T) t); - } - - converter = toObjects - .stream() - .filter(c -> clazz.isAssignableFrom(c.getTargetType())) - .findFirst(); - - if (converter.isPresent()) { - return (U) converter.get().toObject((T) t); - } - - if (logWarnings) { - LOGGER.warn(SemanticKernelResources.getString("no.converter.found.for.to"), - t.getClass(), - clazz); - } - return null; - } - - /** - * Convert the object to the type of the context variable using the {@code fromObject} function - * provided to the constructor. - * - * @param s the object to convert - * @return the converted object - */ - @Nullable - public T fromObject(@Nullable Object s) { - if (s == null) { - return null; - } - if (s instanceof ContextVariable) { - return fromObject.apply(((ContextVariable) s).getValue()); - } - return fromObject.apply(s); - } - - /** - * Convert the type to a prompt string using the {@code toPromptString} function provided to the - * constructor. - * - * @param types the context variable types, if {@code null} the global types are used - * @param t the type to convert - * @return the prompt string - */ - public String toPromptString(@Nullable ContextVariableTypes types, @Nullable T t) { - if (t == null) { - return ""; - } - if (types == null) { - types = ContextVariableTypes.getGlobalTypes(); - } - return toPromptString.toPromptString(types, t); - } - - /** - * Convert the prompt string to the type using the {@code fromPromptString} function provided to - * the constructor. - * - * @param t the prompt string to convert - * @return the type - */ - @Nullable - public T fromPromptString(@Nullable String t) { - if (t == null) { - return null; - } - return fromPromptString.apply(t); - } - - /** - * Get the class of the type. - * - * @return the class of the type - */ - public Class getType() { - return clazz; - } - - /** - * A converter from one type to another. - * - * @param the source type - * @param the target type - */ - public interface Converter { - - /** - * Convert the object to the target type. - * - * @param t the object to convert - * @return the converted object - */ - U toObject(T t); - - /** - * Get the class of the target type. - * - * @return the class of the target type - */ - Class getTargetType(); - } - - /** - * A converter that does no conversion. This converter is often used as a default when no other - * converter can be found for the type. - * - * @param the type of the context variable - */ - public static class NoopConverter extends ContextVariableTypeConverter { - - /** - * Create a new noop converter. - * - * @param clazz the class of the type - */ - public NoopConverter(Class clazz) { - super( - clazz, - x -> { - return (T) x; - }, - x -> { - throw new RuntimeException("Noop converter should not be called"); - }, - x -> { - throw new RuntimeException("Noop converter should not be called"); - }); - } - } - - /** - * A base class for concrete implementations of {@link ContextVariableTypeConverter.Converter}. - * - * @param the source type - * @param the target type - */ - public static abstract class DefaultConverter implements Converter { - - private final Class targetType; - - protected DefaultConverter(Class sourceType, Class targetType) { - this.targetType = targetType; - } - - @Override - public Class getTargetType() { - return targetType; - } - } - - /** - * Create a new builder for a context variable type converter. - * - * @param the type of the context variable - * @param clazz the class of the type - * @return the builder - */ - public static Builder builder(Class clazz) { - return new Builder<>(clazz); - } - - /** - * A builder for a context variable type converter. - * @param the type of the context variable - */ - public static class Builder { - - private final Class clazz; - private Function fromObject; - private ToPromptStringFunction toPromptString; - private Function fromPromptString; - - /** - * Create a new builder for a context variable type converter. - * - * @param clazz the class of the type - */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") - public Builder(Class clazz) { - this.clazz = clazz; - fromObject = x -> ContextVariableTypes.convert(x, clazz); - toPromptString = (a, b) -> { - throw new UnsupportedOperationException("toPromptString not implemented"); - }; - fromPromptString = x -> { - throw new UnsupportedOperationException("fromPromptString not implemented"); - }; - } - - /** - * Make this builder a proxy for another type converter. - * - * @return this builder - */ - public Builder proxyGlobalType() { - ContextVariableType existingType = ContextVariableTypes - .getGlobalVariableTypeForClass( - clazz); - if (existingType == null) { - throw new SKException( - "Asked to proxy a global type that does not exist: " + clazz.getName()); - } - return proxyType(existingType.getConverter()); - } - - /** - * Make this builder a proxy for another type converter. - * - * @param proxy the proxy type converter - * @return this builder - */ - public Builder proxyType(ContextVariableTypeConverter proxy) { - this.fromObject = proxy.fromObject; - this.toPromptString = proxy.toPromptString; - this.fromPromptString = proxy.fromPromptString; - return this; - } - - /** - * Set the function to convert an object to the type. - * - * @param fromObject the function to convert an object to the type - * @return this builder - */ - public Builder fromObject(Function fromObject) { - this.fromObject = fromObject; - return this; - } - - /** - * Set the function to convert the type to a prompt string. - * - * @param toPromptString the function to convert the type to a prompt string - * @return this builder - */ - public Builder toPromptString(Function toPromptString) { - this.toPromptString = (ignore, a) -> toPromptString.apply(a); - return this; - } - - /** - * Set the function to convert a prompt string to the type. - * - * @param fromPromptString the function to convert a prompt string to the type - * @return this builder - */ - public Builder fromPromptString(Function fromPromptString) { - this.fromPromptString = fromPromptString; - return this; - } - - /** - * Build the context variable type converter. - * - * @return the context variable type converter - */ - public ContextVariableTypeConverter build() { - return new ContextVariableTypeConverter<>( - clazz, - fromObject, - toPromptString, - fromPromptString); - } - } - - /** - * To be used when toPromptString is called - * - * @param value the value to escape - * @return the escaped value - */ - @Nullable - public static String escapeXmlString(@Nullable String value) { - if (value == null) { - return null; - } - return StringEscapeUtils.escapeXml11(value); - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypes.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypes.java deleted file mode 100644 index dd12bb706..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypes.java +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables; - -import com.microsoft.semantickernel.contextvariables.converters.BooleanVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.CharacterVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.ChatHistoryVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.CollectionVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.CompletionUsageContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.DateTimeContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.InstantContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.NumberVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.PrimitiveBooleanVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.StringVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.TextContentVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.VoidVariableContextVariableTypeConverter; -import com.microsoft.semantickernel.exceptions.SKException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * A collection of context variable types, with converters to convert objects to the types. - */ -public class ContextVariableTypes { - - private static final ContextVariableTypes DEFAULT_TYPES; - - static { - List> types = Arrays.asList( - new CharacterVariableContextVariableTypeConverter(), - new ChatHistoryVariableContextVariableTypeConverter(), - new TextContentVariableContextVariableTypeConverter(), - new StringVariableContextVariableTypeConverter(), - new CollectionVariableContextVariableTypeConverter(), - new VoidVariableContextVariableTypeConverter(), - new ContextVariableTypeConverter<>(void.class, s -> null, s -> null, s -> null), - new DateTimeContextVariableTypeConverter(), - new InstantContextVariableTypeConverter(), - new CompletionUsageContextVariableTypeConverter(), - - new BooleanVariableContextVariableTypeConverter(), - new PrimitiveBooleanVariableContextVariableTypeConverter(), - - new NumberVariableContextVariableTypeConverter<>(Byte.class, Byte::parseByte, - Number::byteValue), - new NumberVariableContextVariableTypeConverter<>(byte.class, Byte::parseByte, - Number::byteValue), - - new NumberVariableContextVariableTypeConverter<>(Integer.class, Integer::parseInt, - Number::intValue), - new NumberVariableContextVariableTypeConverter<>(int.class, Integer::parseInt, - Number::intValue), - - new NumberVariableContextVariableTypeConverter<>(Long.class, Long::parseLong, - Number::longValue), - new NumberVariableContextVariableTypeConverter<>(long.class, Long::parseLong, - Number::longValue), - - new NumberVariableContextVariableTypeConverter<>(Double.class, Double::parseDouble, - Number::doubleValue), - new NumberVariableContextVariableTypeConverter<>(double.class, Double::parseDouble, - Number::doubleValue), - - new NumberVariableContextVariableTypeConverter<>(Float.class, Float::parseFloat, - Number::floatValue), - new NumberVariableContextVariableTypeConverter<>(float.class, Float::parseFloat, - Number::floatValue), - - new NumberVariableContextVariableTypeConverter<>(Short.class, Short::parseShort, - Number::shortValue), - new NumberVariableContextVariableTypeConverter<>(short.class, Short::parseShort, - Number::shortValue)); - DEFAULT_TYPES = new ContextVariableTypes(types); - } - - private final Map, ContextVariableType> variableTypes; - - /** - * Create a new collection of context variable types. - * - * @param converters The converters to use to convert objects to the types. - */ - public ContextVariableTypes(List> converters) { - variableTypes = new HashMap<>(); - converters.forEach(this::putConverter); - } - - /** - * Create a new collection of context variable types. - */ - public ContextVariableTypes() { - variableTypes = new HashMap<>(); - } - - /** - * Get the globally available collectors, which is the - * default collection of context variable types and those that - * have been added with - * {@link #addGlobalConverter(ContextVariableTypeConverter)}. - * - * @return The collection of globally available converters. - */ - public static ContextVariableTypes getGlobalTypes() { - return new ContextVariableTypes(DEFAULT_TYPES); - } - - /** - * Create a new collection of context variable types. - * - * @param contextVariableTypes The collection of context variable types to copy. - */ - public ContextVariableTypes(ContextVariableTypes contextVariableTypes) { - if (contextVariableTypes != null) { - this.variableTypes = new HashMap<>(contextVariableTypes.variableTypes); - } else { - this.variableTypes = new HashMap<>(); - } - } - - /** - * Add a converter to the global collection of context variable type converters. - * - * @param converter The converter to add. - * @see #getGlobalVariableTypeForClass(Class) - */ - public static void addGlobalConverter( - ContextVariableTypeConverter converter) { - DEFAULT_TYPES.putConverter(converter); - } - - /** - * Get the global context variable type for the given class. - * - * @param aClass The class to get the context variable type for. - * @param The type of the context variable. - * @return The context variable type for the given class. - * @see #addGlobalConverter(ContextVariableTypeConverter) - */ - public static ContextVariableType getGlobalVariableTypeForClass(Class aClass) { - return DEFAULT_TYPES.getVariableTypeForClass(aClass); - } - - /** - * Convert the given object to the given class, if possible. - * - * @param the type to convert to - * @param s the object to convert - * @param clazz the class of the type to convert to - * @return the converted object, or {@code null} if the object cannot be converted - */ - @Nullable - @SuppressWarnings("unchecked") - public static T convert(@Nullable Object s, Class clazz) { - if (s instanceof ContextVariable && ((ContextVariable) s).getType().getClazz() - .isAssignableFrom(clazz)) { - return ((ContextVariable) s).getValue(); - } - if (s != null && clazz.isAssignableFrom(s.getClass())) { - return clazz.cast(s); - } else { - return null; - } - } - - /** - * Add a converter to this {@code ContextVariableTypes} instance. - * - * @param The type of the context variable. - * @param contextVariableTypeConverter the converter to add. - */ - public void putConverter( - ContextVariableTypeConverter contextVariableTypeConverter) { - variableTypes.put(contextVariableTypeConverter.getType(), - new ContextVariableType<>(contextVariableTypeConverter, - contextVariableTypeConverter.getType())); - } - - /** - * Get the context variable type for the given class. - * - * @param aClass The class to get the context variable type for. - * @param The type of the context variable. - * @return The context variable type for the given class - * @throws SKException if the type cannot be found. - */ - @SuppressWarnings("unchecked") - public ContextVariableType getVariableTypeForClass(Class aClass) { - try { - return this.getVariableTypeForClassInternal(aClass); - } catch (Exception e) { - return DEFAULT_TYPES.getVariableTypeForClassInternal(aClass); - } - } - - /** - * Get the context variable type for the given class or for a type that is assignable from the - * given class. its super class. - * - * @param aClass The class to get the context variable type for. - * @param The type of the context variable. - * @return The context variable type for the given class. - * @throws SKException if the type cannot be found. - */ - @SuppressWarnings("unchecked") - public ContextVariableType getVariableTypeForSuperClass(Class aClass) { - try { - return this.getVariableTypeForSuperClassInternal(aClass); - } catch (Exception e) { - return DEFAULT_TYPES.getVariableTypeForSuperClassInternal(aClass); - } - } - - @SuppressWarnings("unchecked") - private ContextVariableType getVariableTypeForClassInternal(Class aClass) { - ContextVariableType contextVariableType = variableTypes.get(aClass); - - if (contextVariableType != null) { - return (ContextVariableType) contextVariableType; - } - - return (ContextVariableType) variableTypes - .values() - .stream() - .filter(c -> { - return c.getClazz().isAssignableFrom(aClass); - }) - .findFirst() - .orElseThrow( - () -> new SKException("Unknown context variable type: " + aClass.getName())); - } - - @SuppressWarnings("unchecked") - private ContextVariableType getVariableTypeForSuperClassInternal(Class aClass) { - ContextVariableType contextVariableType = variableTypes.get(aClass); - - if (contextVariableType != null) { - return (ContextVariableType) contextVariableType; - } - - return (ContextVariableType) variableTypes - .values() - .stream() - .filter(c -> { - return aClass.isAssignableFrom(c.getClazz()); - }) - .findFirst() - .orElseThrow( - () -> new SKException("Unknown context variable type: " + aClass.getName())); - } - - /** - * Add all the converters from the given collection to this collection. - * - * @param contextVariableTypes The collection of converters to add. - */ - public void putConverters(ContextVariableTypes contextVariableTypes) { - this.variableTypes.putAll(contextVariableTypes.variableTypes); - } - - /** - * Create a context variable of the given value. - * - * @param value The value to create a context variable of. - * @param The type of the context variable. - * @return The context variable of the given value. - */ - public ContextVariable contextVariableOf(T value) { - if (value instanceof ContextVariable) { - return (ContextVariable) value; - } - - ContextVariableType type = getVariableTypeForClass(value.getClass()); - - if (type == null) { - throw new SKException("Unknown type: " + value.getClass()); - } - - return (ContextVariable) type.of(value); - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/BooleanVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/BooleanVariableContextVariableTypeConverter.java deleted file mode 100644 index 4769064a1..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/BooleanVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; - -/** - * A {@link ContextVariableTypeConverter} for {@link Boolean} variables. Use - * {@code ContextVariableTypes.getDefaultVariableTypeForClass(Boolean.class)} to get an instance of - * this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class BooleanVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Initializes a new instance of the {@link BooleanVariableContextVariableTypeConverter} class. - */ - public BooleanVariableContextVariableTypeConverter() { - super( - Boolean.class, - s -> convert(s, Boolean.class), - Object::toString, - Boolean::parseBoolean); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CharacterVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CharacterVariableContextVariableTypeConverter.java deleted file mode 100644 index 2629c0e4a..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CharacterVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.lang.Character} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(Character.class)} to get an instance of - * this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class CharacterVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Initializes a new instance of the {@link CharacterVariableContextVariableTypeConverter} - * class. - */ - public CharacterVariableContextVariableTypeConverter() { - super( - Character.class, - s -> convert(s, Character.class), - Object::toString, - CharacterVariableContextVariableTypeConverter::charFromPromptString); - } - - /* - * Converts a prompt string to a Character. - */ - static Character charFromPromptString(String s) { - if (s.length() != 1) { - throw new SKException("Cannot convert string to character: " + s); - } - return s.charAt(0); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ChatHistoryVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ChatHistoryVariableContextVariableTypeConverter.java deleted file mode 100644 index 92e331e3f..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ChatHistoryVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import java.util.stream.Collectors; - -/** - * A {@link ContextVariableTypeConverter} for - * {@code com.microsoft.semantickernel.chathistory.ChatHistory} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(ChatHistory.class)} to get an instance - * of this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class ChatHistoryVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Initializes a new instance of the {@link ChatHistoryVariableContextVariableTypeConverter} - * class. - */ - public ChatHistoryVariableContextVariableTypeConverter() { - super( - ChatHistory.class, - s -> convert(s, ChatHistory.class), - ChatHistoryVariableContextVariableTypeConverter::toXmlString, - x -> { - throw new UnsupportedOperationException( - "ChatHistoryVariableConverter does not support fromPromptString"); - }); - } - - /* - * Converts a {@link ChatHistory} to an XML string. - */ - private static String toXmlString(ChatHistory chatHistory) { - String messages = chatHistory - .getMessages() - .stream() - .map(message -> String.format("%s", - message.getAuthorRole(), - escapeXmlString(message.getContent()))) - .collect(Collectors.joining("\n")); - - return String.format("%n%s%n", messages); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java deleted file mode 100644 index d7bf72e00..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.Collection; -import java.util.stream.Collectors; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.util.Collection} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(String.class)} to get an instance of - * this class. - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class CollectionVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link CollectionVariableContextVariableTypeConverter} class. - * @param delimiter The delimiter to use joining elements of the collection. - */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") - public CollectionVariableContextVariableTypeConverter(String delimiter) { - super( - Collection.class, - s -> convert(s, Collection.class), - getString(delimiter), - s -> { - throw new UnsupportedOperationException(); - }); - } - - /** - * Creates a new instance of the {@link CollectionVariableContextVariableTypeConverter} class. - */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") - public CollectionVariableContextVariableTypeConverter() { - this(","); - } - - /** - * Gets a function that converts a collection to a string. - * @param delimiter The delimiter to use joining elements of the collection. - * @return A function that converts a collection to a string. - */ - @SuppressWarnings("NullAway") - public static ToPromptStringFunction getString(String delimiter) { - return (types, collection) -> { - String formatted = (String) collection - .stream() - .map(t -> getString(types, t)) - .collect(Collectors.joining(delimiter)); - - return escapeXmlString(formatted); - }; - } - - private static String getString(ContextVariableTypes types, Object t) { - if (t instanceof ContextVariable) { - return ((ContextVariable) t).toPromptString(types); - } else { - ContextVariableType converter = types.getVariableTypeForClass( - t.getClass()); - - if (converter != null) { - return converter.getConverter().toPromptString(types, t); - } - return t.toString(); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CompletionUsageContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CompletionUsageContextVariableTypeConverter.java deleted file mode 100644 index 048afc19e..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CompletionUsageContextVariableTypeConverter.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.azure.ai.openai.models.CompletionsUsage; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; - -/** - * A {@link ContextVariableTypeConverter} for {@code com.azure.ai.openai.models.CompletionsUsage} - * variables. Use {@code ContextVariableTypes.getGlobalVariableTypeForClass(CompletionsUsage.class)} - * to get an instance of this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class CompletionUsageContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link CompletionUsageContextVariableTypeConverter} class. - */ - public CompletionUsageContextVariableTypeConverter() { - super( - CompletionsUsage.class, - s -> { - if (s instanceof CompletionsUsage) { - return (CompletionsUsage) s; - } - return null; - }, - Object::toString, - o -> null // Do not support parsing from string - ); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableJacksonConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableJacksonConverter.java deleted file mode 100644 index ca4bfc448..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableJacksonConverter.java +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter.Builder; -import com.microsoft.semantickernel.exceptions.SKException; - -/** - * A utility class for creating {@link ContextVariableTypeConverter} instances that use Jackson for - * serialization and deserialization. - */ -public final class ContextVariableJacksonConverter { - - /** - * Creates a new {@link ContextVariableTypeConverter} that uses Jackson for serialization and - * deserialization. - * - * @param type the type of the context variable - * @param mapper the {@link ObjectMapper} to use for serialization and deserialization - * @param the type of the context variable - * @return a new {@link ContextVariableTypeConverter} - */ - public static ContextVariableTypeConverter create(Class type, ObjectMapper mapper) { - return builder(type, mapper).build(); - } - - /** - * Creates a new {@link ContextVariableTypeConverter} that uses Jackson for serialization and - * deserialization. - * - * @param type the type of the context variable - * @param the type of the context variable - * @return a new {@link ContextVariableTypeConverter} - */ - public static ContextVariableTypeConverter create(Class type) { - return create(type, new ObjectMapper()); - } - - /** - * Creates a new {@link Builder} for a {@link ContextVariableTypeConverter} that uses Jackson - * for serialization and deserialization. - * - * @param type the type of the context variable - * @param the type of the context variable - * @return a new {@link Builder} - */ - public static Builder builder(Class type) { - return builder(type, new ObjectMapper()); - } - - /** - * Creates a new {@link Builder} for a {@link ContextVariableTypeConverter} that uses Jackson - * for serialization and deserialization. - * - * @param type the type of the context variable - * @param mapper the {@link ObjectMapper} to use for serialization and deserialization - * @param the type of the context variable - * @return a new {@link Builder} - */ - public static Builder builder(Class type, ObjectMapper mapper) { - return ContextVariableTypeConverter.builder(type) - .fromPromptString(str -> { - try { - return mapper.readValue(str, type); - } catch (JsonProcessingException e) { - throw new SKException("Failed to deserialize object", e); - } - }) - .toPromptString(obj -> { - try { - return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); - } catch (JsonProcessingException e) { - throw new SKException("Failed to serialize object", e); - } - }); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/DateTimeContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/DateTimeContextVariableTypeConverter.java deleted file mode 100644 index 34fc741f1..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/DateTimeContextVariableTypeConverter.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZonedDateTime; -import java.util.Arrays; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.time.OffsetDateTime} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(OffsetDateTime.class)} to get an - * instance of this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class DateTimeContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link DateTimeContextVariableTypeConverter} class. - */ - public DateTimeContextVariableTypeConverter() { - super( - OffsetDateTime.class, - s -> { - if (s instanceof String) { - return ZonedDateTime.parse((String) s).toOffsetDateTime(); - } else if (s instanceof OffsetDateTime) { - return (OffsetDateTime) s; - } - return null; - }, - Object::toString, - o -> ZonedDateTime.parse(o).toOffsetDateTime(), - Arrays.asList( - new DefaultConverter(OffsetDateTime.class, Instant.class) { - @Override - public Instant toObject(OffsetDateTime offsetDateTime) { - return offsetDateTime.toInstant(); - } - })); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/InstantContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/InstantContextVariableTypeConverter.java deleted file mode 100644 index 13fbfb4e1..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/InstantContextVariableTypeConverter.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.time.Instant; -import java.time.OffsetDateTime; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.time.Instant} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(Instant.class)} to get an instance of - * this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class InstantContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link InstantContextVariableTypeConverter} class. - */ - public InstantContextVariableTypeConverter() { - super( - Instant.class, - s -> { - if (s instanceof String) { - return Instant.parse((String) s); - } else if (s instanceof OffsetDateTime) { - return ((OffsetDateTime) s).toInstant(); - } - return null; - }, - Object::toString, - o -> { - return Instant.parse(o); - }); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverter.java deleted file mode 100644 index 2720d1765..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.util.function.Function; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.lang.Number} type variables. Use, for - * example, {@code ContextVariableTypes.getGlobalVariableTypeForClass(Integer.class)} to get an - * instance of this class that works with the {@code Integer} type. - * - * @param the type of the number - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class NumberVariableContextVariableTypeConverter extends - PrimitiveVariableContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link NumberVariableContextVariableTypeConverter} class. - * - * @param clazz the class - * @param fromPromptString the function to convert from a prompt string - * @param fromNumber the function to convert from a number - */ - public NumberVariableContextVariableTypeConverter( - Class clazz, - Function fromPromptString, - Function fromNumber) { - super( - clazz, - fromPromptString, - num -> { - if (num instanceof Number) { - return fromNumber.apply((Number) num); - } else { - return null; - } - }, - Number::toString); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveBooleanVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveBooleanVariableContextVariableTypeConverter.java deleted file mode 100644 index 0124fe346..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveBooleanVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.util.Locale; - -/** - * A {@link ContextVariableTypeConverter} for {@link Boolean} variables. Use - * {@code ContextVariableTypes.getDefaultVariableTypeForClass(Boolean.class)} to get an instance of - * this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class PrimitiveBooleanVariableContextVariableTypeConverter extends - PrimitiveVariableContextVariableTypeConverter { - - /** - * Initializes a new instance of the - * {@link PrimitiveBooleanVariableContextVariableTypeConverter} class. - */ - public PrimitiveBooleanVariableContextVariableTypeConverter() { - super( - boolean.class, - s -> { - switch (((String) s).toLowerCase(Locale.ROOT).trim()) { - case "true": - case "on": - case "1": - case "yes": - case "y": - case "t": - case "enable": - return true; - case "false": - case "off": - case "0": - case "no": - case "n": - case "f": - case "disable": - return false; - default: - return null; - } - }, - s -> { - if (s instanceof Boolean || boolean.class.isInstance(s)) { - return s; - } - return null; - }, - s -> { - if (s == null) { - return null; - } - return ((Boolean) s).toString(); - }); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveVariableContextVariableTypeConverter.java deleted file mode 100644 index 310ceab09..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/PrimitiveVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.util.function.Function; -import javax.annotation.Nullable; - -/** - * A {@link ContextVariableTypeConverter} for primitive variables. - * - * @param the type of the variable - */ -public class PrimitiveVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - private final Function fromObject; - - /** - * Creates a new instance of the {@link PrimitiveVariableContextVariableTypeConverter} class. - * - * @param clazz the class - * @param fromPromptString the function to convert from a prompt string - * @param fromObject the function to convert from an object to primitive - * @param toPromptString the function to convert to a prompt string - */ - public PrimitiveVariableContextVariableTypeConverter( - Class clazz, - Function fromPromptString, - Function fromObject, - Function toPromptString) { - super( - clazz, - s -> convert(s, clazz), - s -> escapeXmlString(toPromptString.apply(s)), - fromPromptString); - this.fromObject = fromObject; - } - - @Override - @Nullable - public U toObject(ContextVariableTypes types, @Nullable Object t, Class clazz) { - if (t == null) { - return null; - } - - // Let the parent class have a crack at it first - // since someone may have installed a special converter. - U obj = super.toObject(types, t, clazz); - if (obj != null) { - return obj; - } - // If the type is a string, and the object is of the same type as the - // converter, then we can convert with the toPromptString method. - if (clazz == String.class && t.getClass() == super.getType()) { - return clazz.cast(toPromptString(types, getType().cast(t))); - } - return null; - } - - @Override - @Nullable - public T fromObject(@Nullable Object s) { - if (s instanceof ContextVariable) { - s = ((ContextVariable) s).getValue(); - } - - T obj = super.fromObject(s); - if (obj != null) { - return obj; - } - - try { - T result = fromObject.apply(s); - if (result != null) { - return result; - } - } catch (Exception e) { - // ignore - } - - if (s instanceof String) { - return fromPromptString((String) s); - } - return null; - } - - @Override - @Nullable - public T fromPromptString(@Nullable String s) { - if (s != null && !s.isEmpty()) { - return super.fromPromptString(s); - } - return null; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/StringVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/StringVariableContextVariableTypeConverter.java deleted file mode 100644 index 3e303bff6..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/StringVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import javax.annotation.Nullable; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.lang.String} variables. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(String.class)} to get an instance of - * this class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class StringVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link StringVariableContextVariableTypeConverter} class. - */ - public StringVariableContextVariableTypeConverter() { - super( - String.class, - StringVariableContextVariableTypeConverter::convertToString, - ContextVariableTypeConverter::escapeXmlString, - s -> s); - } - - /** - * Converts the specified object to a string. - * Has special handling for {@link ContextVariable} objects and - * for objects that look like an object reference - * @param s the object to convert - * @return the string representation of the object, or {@code null} - * if the object cannot be converted to a string or is an object reference. - */ - @Nullable - public static String convertToString(@Nullable Object s) { - String converted = convert(s, String.class); - if (converted != null) { - return converted; - } - - if (s instanceof ContextVariable) { - s = ((ContextVariable) s).getValue(); - } - - if (s != null) { - String str = s.toString(); - // ignore if this looks like an object reference - if (!str.matches(".*@[a-f0-9]+$")) { - return str; - } - } - return null; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/TextContentVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/TextContentVariableContextVariableTypeConverter.java deleted file mode 100644 index 920ac4a18..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/TextContentVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.services.textcompletion.TextContent; -import javax.annotation.Nullable; - -/** - * A converter for a context variable type. This class is used to convert objects to and from a - * prompt string, and to convert objects to the type of the context variable. - */ -public class TextContentVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Initializes a new instance of the {@link TextContentVariableContextVariableTypeConverter} - * class. - */ - public TextContentVariableContextVariableTypeConverter() { - super( - TextContent.class, - s -> convert(s, TextContent.class), - TextContentVariableContextVariableTypeConverter::escapeXmlStringValue, - x -> { - throw new UnsupportedOperationException( - "TextContentVariableContextVariableTypeConverter does not support fromPromptString"); - }); - } - - /** - * Escapes the XML string value. - * @param value The value containing the content to escape. - * @return The escaped XML string value. - * @see ContextVariableTypeConverter#escapeXmlString(String) - */ - @Nullable - public static String escapeXmlStringValue(@Nullable TextContent value) { - if (value == null) { - return null; - } - return escapeXmlString(value.getContent()); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/VoidVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/VoidVariableContextVariableTypeConverter.java deleted file mode 100644 index d3d602c1c..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/VoidVariableContextVariableTypeConverter.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; - -/** - * A {@link ContextVariableTypeConverter} for {@code java.lang.Void} types. Use - * {@code ContextVariableTypes.getGlobalVariableTypeForClass(Void.class)} to get an instance of this - * class. - * - * @see ContextVariableTypes#getGlobalVariableTypeForClass(Class) - */ -public class VoidVariableContextVariableTypeConverter extends - ContextVariableTypeConverter { - - /** - * Creates a new instance of the {@link VoidVariableContextVariableTypeConverter} class. - */ - public VoidVariableContextVariableTypeConverter() { - super( - Void.class, - s -> null, - s -> null, - s -> null); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java deleted file mode 100644 index b4993f44c..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.functionchoice; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; - -import javax.annotation.Nullable; -import java.util.List; - -/** - * A set of allowed kernel functions. All kernel functions are allowed if allKernelFunctionsAllowed is true. - * Otherwise, only the functions in allowedFunctions are allowed. - *

- * If a function is allowed, it may be called. If it is not allowed, it will not be called. - */ -public class AutoFunctionChoiceBehavior extends FunctionChoiceBehavior { - private final boolean autoInvoke; - - /** - * Create a new instance of AutoFunctionChoiceBehavior. - * - * @param autoInvoke Whether auto-invocation is enabled. - * @param functions A set of functions to advertise to the model. - * @param options Options for the function choice behavior. - */ - public AutoFunctionChoiceBehavior(boolean autoInvoke, - @Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - super(functions, options); - this.autoInvoke = autoInvoke; - } - - /** - * Check whether the given function is allowed. - * - * @return Whether the function is allowed. - */ - public boolean isAutoInvoke() { - return autoInvoke; - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java deleted file mode 100644 index d74a77a79..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.functionchoice; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; - -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Defines the behavior of a tool call. Currently, the only tool available is function calling. - */ -public abstract class FunctionChoiceBehavior { - private final Set fullFunctionNames; - - protected final List> functions; - protected final FunctionChoiceBehaviorOptions options; - - protected FunctionChoiceBehavior(@Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - this.functions = functions != null ? Collections.unmodifiableList(functions) : null; - this.fullFunctionNames = new HashSet<>(); - - if (functions != null) { - functions.stream().filter(Objects::nonNull).forEach( - f -> this.fullFunctionNames - .add(formFullFunctionName(f.getPluginName(), f.getName()))); - } - - if (options != null) { - this.options = options; - } else { - this.options = FunctionChoiceBehaviorOptions.builder().build(); - } - } - - /** - * Gets the functions that are allowed. - * - * @return The functions that are allowed. - */ - public List> getFunctions() { - return Collections.unmodifiableList(functions); - } - - /** - * Gets the options for the function choice behavior. - * - * @return The options for the function choice behavior. - */ - public FunctionChoiceBehaviorOptions getOptions() { - return options; - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides all the Kernel's plugins functions to the AI model to call. - * - * @param autoInvoke Indicates whether the functions should be automatically invoked by AI connectors - * - * @return A new ToolCallBehavior instance with all kernel functions allowed. - */ - public static FunctionChoiceBehavior auto(boolean autoInvoke) { - return new AutoFunctionChoiceBehavior(autoInvoke, null, null); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - * - * @param autoInvoke Enable or disable auto-invocation. - * If auto-invocation is enabled, the model may request that the Semantic Kernel - * invoke the kernel functions and return the value to the model. - * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model. - * If empty, no functions are provided to the model, which is equivalent to disabling function calling. - * - * @return A new FunctionChoiceBehavior instance with all kernel functions allowed. - */ - public static FunctionChoiceBehavior auto(boolean autoInvoke, - @Nullable List> functions) { - return new AutoFunctionChoiceBehavior(autoInvoke, functions, null); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - * - * @param autoInvoke Enable or disable auto-invocation. - * If auto-invocation is enabled, the model may request that the Semantic Kernel - * invoke the kernel functions and return the value to the model. - * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model. - * If empty, no functions are provided to the model, which is equivalent to disabling function calling. - * @param options Options for the function choice behavior. - * - * @return A new FunctionChoiceBehavior instance with all kernel functions allowed. - */ - public static FunctionChoiceBehavior auto(boolean autoInvoke, - @Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - return new AutoFunctionChoiceBehavior(autoInvoke, functions, options); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - *

- * This behavior forces the model to call the provided functions. - * SK connectors will invoke a requested function or multiple requested functions if the model requests multiple ones in one request, - * while handling the first request, and stop advertising the functions for the following requests to prevent the model from repeatedly calling the same function(s). - * - * @return A new FunctionChoiceBehavior instance with the required function. - */ - public static FunctionChoiceBehavior required(boolean autoInvoke, - @Nullable List> functions) { - return new RequiredFunctionChoiceBehavior(autoInvoke, functions, null); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - *

- * This behavior forces the model to call the provided functions. - * SK connectors will invoke a requested function or multiple requested functions if the model requests multiple ones in one request, - * while handling the first request, and stop advertising the functions for the following requests to prevent the model from repeatedly calling the same function(s). - * - * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model. - * If empty, no functions are provided to the model, which is equivalent to disabling function calling. - * @return A new FunctionChoiceBehavior instance with the required function. - */ - public static FunctionChoiceBehavior required(boolean autoInvoke, - @Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - return new RequiredFunctionChoiceBehavior(autoInvoke, functions, options); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - *

- * This behavior is useful if the user should first validate what functions the model will use. - */ - public static FunctionChoiceBehavior none() { - return new NoneFunctionChoiceBehavior(null, null); - } - - /** - * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions. - *

- * This behavior is useful if the user should first validate what functions the model will use. - * - * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model. - * If empty, no functions are provided to the model, which is equivalent to disabling function calling. - */ - public static FunctionChoiceBehavior none(@Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - return new NoneFunctionChoiceBehavior(functions, options); - } - - /** - * The separator between the plugin name and the function name. - */ - public static final String FUNCTION_NAME_SEPARATOR = "-"; - - /** - * Form the full function name. - * - * @param pluginName The name of the plugin that the function is in. - * @param functionName The name of the function. - * @return The key for the function. - */ - public static String formFullFunctionName(@Nullable String pluginName, String functionName) { - if (pluginName == null) { - pluginName = ""; - } - return String.format("%s%s%s", pluginName, FUNCTION_NAME_SEPARATOR, functionName); - } - - /** - * Check whether the given function is allowed. - * - * @param function The function to check. - * @return Whether the function is allowed. - */ - public boolean isFunctionAllowed(KernelFunction function) { - return isFunctionAllowed(function.getPluginName(), function.getName()); - } - - /** - * Check whether the given function is allowed. - * - * @param pluginName The name of the plugin that the function is in. - * @param functionName The name of the function. - * @return Whether the function is allowed. - */ - public boolean isFunctionAllowed(@Nullable String pluginName, String functionName) { - // If no functions are provided, all functions are allowed. - if (functions == null || functions.isEmpty()) { - return true; - } - - String key = formFullFunctionName(pluginName, functionName); - return fullFunctionNames.contains(key); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java deleted file mode 100644 index ffb17c780..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.functionchoice; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; - -public class FunctionChoiceBehaviorOptions { - private final boolean parallelCallsAllowed; - - private FunctionChoiceBehaviorOptions(boolean parallelCallsAllowed) { - this.parallelCallsAllowed = parallelCallsAllowed; - } - - /** - * Returns a new builder for {@link FunctionChoiceBehaviorOptions}. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Indicates whether parallel calls to functions are allowed. - * - * @return True if parallel calls are allowed; otherwise, false. - */ - public boolean isParallelCallsAllowed() { - return parallelCallsAllowed; - } - - /** - * Builder for {@link FunctionChoiceBehaviorOptions}. - */ - public static class Builder implements SemanticKernelBuilder { - private boolean allowParallelCalls = false; - - /** - * Sets whether parallel calls to functions are allowed. - * - * @param allowParallelCalls True if parallel calls are allowed; otherwise, false. - * @return The builder instance. - */ - public Builder withParallelCallsAllowed(boolean allowParallelCalls) { - this.allowParallelCalls = allowParallelCalls; - return this; - } - - public FunctionChoiceBehaviorOptions build() { - return new FunctionChoiceBehaviorOptions(allowParallelCalls); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java deleted file mode 100644 index 1842ba5fc..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.functionchoice; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; - -import javax.annotation.Nullable; -import java.util.List; - -public class NoneFunctionChoiceBehavior extends FunctionChoiceBehavior { - - /** - * Create a new instance of NoneFunctionChoiceBehavior. - */ - public NoneFunctionChoiceBehavior(@Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - super(functions, options); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java deleted file mode 100644 index 8bfee535b..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.functionchoice; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; - -import javax.annotation.Nullable; -import java.util.List; - -public class RequiredFunctionChoiceBehavior extends AutoFunctionChoiceBehavior { - - /** - * Create a new instance of RequiredFunctionChoiceBehavior. - * - * @param autoInvoke Whether auto-invocation is enabled. - * @param functions A set of functions to advertise to the model. - * @param options Options for the function choice behavior. - */ - public RequiredFunctionChoiceBehavior(boolean autoInvoke, - @Nullable List> functions, - @Nullable FunctionChoiceBehaviorOptions options) { - super(autoInvoke, functions, options); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java deleted file mode 100644 index 7a39cdfe8..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Represents a KernelHookEvent that is raised after a function is invoked. - * - * @param The type of the function result - */ -public class FunctionInvokedEvent implements KernelHookEvent { - - private final KernelFunction function; - @Nullable - private final KernelArguments arguments; - private final FunctionResult result; - - /** - * Creates a new instance of the {@link FunctionInvokedEvent} class. - * - * @param function the function - * @param arguments the arguments - * @param result the result - */ - public FunctionInvokedEvent( - KernelFunction function, - @Nullable KernelArguments arguments, - FunctionResult result) { - this.function = function; - this.arguments = KernelArguments.builder().withVariables(arguments).build(); - this.result = result; - } - - /** - * Gets the function that was invoked. - * - * @return the function - */ - public KernelFunction getFunction() { - return function; - } - - /** - * Gets the arguments that were passed to the function. - * - * @return the arguments - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - @Nullable - public KernelArguments getArguments() { - return arguments; - } - - /** - * Gets the result of the function invocation. - * - * @return the result - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public FunctionResult getResult() { - return result; - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java deleted file mode 100644 index ca360a760..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Represents a KernelHookEvent that is raised before a function is invoked. This event is raised - * before the function is invoked, and can be used to by a {@code KernelHook} to modify the - * arguments before the function is invoked. - * - * @param The type of the KernelFunction being invoked - */ -public class FunctionInvokingEvent implements KernelHookEvent { - - private final KernelFunction function; - private final KernelArguments arguments; - - /** - * Creates a new instance of the FunctionInvokingEvent class. - * - * @param function The function that is being invoked - * @param arguments The arguments that are being passed to the function - */ - public FunctionInvokingEvent(KernelFunction function, - @Nullable KernelArguments arguments) { - this.function = function; - this.arguments = KernelArguments.builder().withVariables(arguments).build(); - } - - /** - * Gets the function that is being invoked. - * - * @return the function - */ - public KernelFunction getFunction() { - return function; - } - - /** - * Gets the arguments that are being passed to the function. - * - * @return the arguments - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelArguments getArguments() { - return arguments; - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java deleted file mode 100644 index e4d3f5300..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.azure.ai.openai.models.ChatCompletionsOptions; -import com.azure.ai.openai.models.ChatRequestMessage; -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Represents a hook that can be used to intercept and modify arguments to {@code KernelFunction}s. - * A {@code KernelHook} implements a {@code Predicate} that determines if the hook is interested in - * a particular event, and a {@code Function} that can be used to modify the event. The - * - * @param The type of the event that the hook is interested in - */ -public interface KernelHook extends Predicate, - Function { - - /** - * The priority of the hook. The default priority is 50. The priority is used to determine the - * order in which hooks that accept the same event type are executed, lower priorities are - * executed first. No ordering is guaranteed for hooks with the same priority. - * - * @return the priority of the hook - */ - default int getPriority() { - return 50; - } - - /** - * A hook that accepts {@link FunctionInvokingEvent} - */ - interface FunctionInvokingHook extends KernelHook> { - - @Override - default boolean test(KernelHookEvent arguments) { - return FunctionInvokingEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link FunctionInvokedEvent} - */ - interface FunctionInvokedHook extends KernelHook> { - - @Override - default boolean test(KernelHookEvent arguments) { - return FunctionInvokedEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link PromptRenderingEvent} - */ - interface PromptRenderingHook extends KernelHook { - - @Override - default boolean test(KernelHookEvent arguments) { - return PromptRenderingEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link PreToolCallEvent} - */ - interface PreToolCallHook extends KernelHook { - - @Override - default boolean test(KernelHookEvent arguments) { - return PreToolCallEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link PromptRenderedEvent} - */ - interface PromptRenderedHook extends KernelHook { - - @Override - default boolean test(KernelHookEvent arguments) { - return PromptRenderedEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link PreChatCompletionEvent} - */ - interface PreChatCompletionHook extends KernelHook { - - /** - * A convenience method to clone the options with the messages from the event. - * - * @param options the options to clone - * @param messages the messages to use - * @return the new options - */ - static ChatCompletionsOptions cloneOptionsWithMessages( - ChatCompletionsOptions options, - List messages) { - - ChatCompletionsOptions newOptions = new ChatCompletionsOptions(messages) - .setPresencePenalty(options.getPresencePenalty()) - .setFrequencyPenalty(options.getFrequencyPenalty()) - .setLogitBias(options.getLogitBias()) - .setMaxTokens(options.getMaxTokens()) - .setModel(options.getModel()) - .setStop(options.getStop()) - .setTemperature(options.getTemperature()) - .setTools(options.getTools()) - .setTopP(options.getTopP()) - .setUser(options.getUser()) - .setDataSources(options.getDataSources()) - .setEnhancements(options.getEnhancements()) - .setFunctions(options.getFunctions()) - .setN(options.getN()) - .setResponseFormat(options.getResponseFormat()) - .setSeed(options.getSeed()); - - if (options.getToolChoice() != null) { - newOptions.setToolChoice(options.getToolChoice()); - } - - if (options.getFunctionCall() != null) { - newOptions = newOptions.setFunctionCall(options.getFunctionCall()); - } - return newOptions; - } - - @Override - default boolean test(KernelHookEvent arguments) { - return PreChatCompletionEvent.class.isAssignableFrom(arguments.getClass()); - } - } - - /** - * A hook that accepts {@link PostChatCompletionEvent} - */ - interface PostChatCompletionHook extends KernelHook { - - @Override - default boolean test(KernelHookEvent arguments) { - return PostChatCompletionEvent.class.isAssignableFrom(arguments.getClass()); - } - - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHookEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHookEvent.java deleted file mode 100644 index 00610ddba..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHookEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -/** - * A marker interface for events that can be intercepted by a {@link KernelHook}. - */ -public interface KernelHookEvent { - -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHooks.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHooks.java deleted file mode 100644 index 959dda5ac..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHooks.java +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook; -import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook; -import com.microsoft.semantickernel.hooks.KernelHook.PostChatCompletionHook; -import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook; -import com.microsoft.semantickernel.hooks.KernelHook.PreToolCallHook; -import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook; -import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; -import javax.annotation.Nullable; - -/** - * Represents a collection of hooks that can be used to intercept and modify events in the kernel. - */ -public class KernelHooks { - - private final Map> hooks; - - /** - * Creates a new instance of the {@link KernelHooks} class. - */ - public KernelHooks() { - this.hooks = new HashMap<>(); - } - - /** - * Creates a copy of the {@link KernelHooks}. - * - * @param kernelHooks the hooks to copy - */ - public KernelHooks(@Nullable KernelHooks kernelHooks) { - this(); - if (kernelHooks != null) { - this.hooks.putAll(kernelHooks.getHooks()); - } - } - - /** - * Creates a new instance of the {@link KernelHooks} class from the given hooks. - * - * @param hooks the hooks to add - */ - public KernelHooks(Map> hooks) { - this(); - this.hooks.putAll(hooks); - } - - /** - * Creates an unmodifiable copy of this {@link KernelHooks}. - * - * @return an unmodifiable copy of this {@link KernelHooks} - */ - public UnmodifiableKernelHooks unmodifiableClone() { - return new UnmodifiableKernelHooks(this); - } - - /** - * Gets the hooks in this collection. - * - * @return an unmodifiable map of the hooks - */ - protected Map> getHooks() { - return Collections.unmodifiableMap(hooks); - } - - /** - * Add a {@link FunctionInvokingHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addFunctionInvokingHook( - Function, FunctionInvokingEvent> function) { - return addHook((FunctionInvokingHook) function::apply); - } - - /** - * Add a {@link FunctionInvokedHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addFunctionInvokedHook( - Function, FunctionInvokedEvent> function) { - return addHook((FunctionInvokedHook) function::apply); - } - - /** - * Add a {@link PreChatCompletionHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addPreChatCompletionHook( - Function function) { - return addHook((PreChatCompletionHook) function::apply); - } - - /** - * Add a {@link PreToolCallHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addPreToolCallHook( - Function function) { - return addHook((PreToolCallHook) function::apply); - } - - /** - * Add a {@link PostChatCompletionEvent} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addPostChatCompletionHook( - Function function) { - return addHook((PostChatCompletionHook) function::apply); - } - - /** - * Add a {@link PromptRenderedHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addPromptRenderedHook( - Function function) { - return addHook((PromptRenderedHook) function::apply); - } - - /** - * Add a {@link PromptRenderingHook} to the collection of hooks. - * - * @param function the function to add - * @return the key of the hook in the collection - */ - public String addPromptRenderingHook( - Function function) { - return addHook((PromptRenderingHook) function::apply); - } - - /** - * Executes the hooks in this collection that accept the event. - * - * @param event the event to execute the hooks on - * @param the type of the event - * @return the event after the hooks have been executed - */ - @SuppressWarnings("unchecked") - public T executeHooks(T event) { - return this.hooks.values() - .stream() - .filter(hook -> hook.test(event)) - .sorted(Comparator.comparingInt(KernelHook::getPriority)) - .reduce(event, (event2, hook) -> { - // unchecked cast - return ((KernelHook) hook).apply(event2); - }, (a, b) -> { - throw new UnsupportedOperationException("No merging for hooks"); - }); - } - - /** - * Add a {@link KernelHook} to the collection of hooks. - * - * @param hook the hook to add - * @return the key of the hook in the collection - */ - public String addHook(KernelHook hook) { - return addHook(UUID.randomUUID().toString(), hook); - } - - /** - * Add a {@link KernelHook} to the collection of hooks. - * - * @param hookName the key of the hook in the collection - * @param hook the hook to add - * @return the key of the hook in the collection - */ - public String addHook(String hookName, KernelHook hook) { - hooks.put(hookName, hook); - return hookName; - } - - /** - * Remove a hook from the collection of hooks. - * - * @param hookName the key of the hook in the collection - * @return the removed hook, or {@code null} if the hook was not found - */ - public KernelHook removeHook(String hookName) { - return hooks.remove(hookName); - } - - /** - * Appends the given hooks to this collection. - * - * @param kernelHooks the hooks to append - * @return this instance of the {@link KernelHooks} class - */ - public KernelHooks addHooks(@Nullable KernelHooks kernelHooks) { - if (kernelHooks == null) { - return this; - } - hooks.putAll(kernelHooks.getHooks()); - - return this; - } - - /** - * Determines if this collection of hooks is empty. - * - * @return {@code true} if the collection is empty, otherwise {@code false} - */ - public boolean isEmpty() { - return hooks.isEmpty(); - } - - /** - * Builds the list of hooks to be invoked for the given context, by merging the hooks in this - * collection with the hooks in the context. Duplicate hooks in b will override hooks in a. - * - * @param a hooks to merge - * @param b hooks to merge - * @return the list of hooks to be invoked - */ - public static KernelHooks merge(@Nullable KernelHooks a, @Nullable KernelHooks b) { - KernelHooks hooks = a; - if (hooks == null) { - hooks = new KernelHooks(); - } - - if (b == null) { - return hooks; - } else if (hooks.isEmpty()) { - return b; - } else { - HashMap> merged = new HashMap<>(hooks.getHooks()); - merged.putAll(b.getHooks()); - return new KernelHooks(merged); - } - } - - /** - * A wrapper for KernelHooks that disables mutating methods. - */ - public static class UnmodifiableKernelHooks extends KernelHooks { - - private UnmodifiableKernelHooks(KernelHooks kernelHooks) { - super(kernelHooks); - } - - @Override - public String addFunctionInvokingHook( - Function, FunctionInvokingEvent> function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addFunctionInvokedHook( - Function, FunctionInvokedEvent> function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addPreChatCompletionHook( - Function function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addPostChatCompletionHook( - Function function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addPromptRenderedHook( - Function function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addPromptRenderingHook( - Function function) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addHook(KernelHook hook) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public String addHook(String hookName, KernelHook hook) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public KernelHooks addHooks(@Nullable KernelHooks kernelHooks) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - - @Override - public KernelHook removeHook(String hookName) { - throw new UnsupportedOperationException("unmodifiable instance of KernelHooks"); - } - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PostChatCompletionEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PostChatCompletionEvent.java deleted file mode 100644 index d824063c2..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PostChatCompletionEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.azure.ai.openai.models.ChatCompletions; - -/** - * Represents a KernelHookEvent that is raised after a chat completion is invoked. - */ -public class PostChatCompletionEvent implements KernelHookEvent { - - private final ChatCompletions chatCompletions; - - /** - * Creates a new instance of the {@link PostChatCompletionEvent} class. - * - * @param chatCompletions the chat completions - */ - public PostChatCompletionEvent(ChatCompletions chatCompletions) { - this.chatCompletions = chatCompletions; - } - - /** - * Gets the chat completions. - * - * @return the chat completions - */ - public ChatCompletions getChatCompletions() { - return chatCompletions; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreChatCompletionEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreChatCompletionEvent.java deleted file mode 100644 index dba2bb9ab..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreChatCompletionEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.azure.ai.openai.models.ChatCompletionsOptions; - -/** - * Represents a KernelHookEvent that is raised before a chat completion is invoked. - */ -public class PreChatCompletionEvent implements KernelHookEvent { - - private final ChatCompletionsOptions options; - - /** - * Creates a new instance of the {@link PreChatCompletionEvent} class. - * - * @param options the chat completion options - */ - public PreChatCompletionEvent(ChatCompletionsOptions options) { - this.options = options; - } - - /** - * Gets the chat completion options. - * - * @return the options - */ - public ChatCompletionsOptions getOptions() { - return options; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java deleted file mode 100644 index 42430f085..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Represents a KernelHookEvent that is raised before a tool call is invoked. - */ -public class PreToolCallEvent implements KernelHookEvent { - - private final ContextVariableTypes contextVariableTypes; - private final String functionName; - @Nullable - private final KernelArguments arguments; - private final KernelFunction function; - - /** - * Creates a new instance of the {@link PreToolCallEvent} class. - * - * @param functionName the name of the function - * @param arguments the arguments - * @param function the function - * @param contextVariableTypes the context variable types - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public PreToolCallEvent( - String functionName, - @Nullable KernelArguments arguments, - KernelFunction function, - ContextVariableTypes contextVariableTypes) { - this.functionName = functionName; - this.arguments = arguments; - this.function = function; - this.contextVariableTypes = contextVariableTypes; - } - - /** - * Gets the tool call arguments. - * @return The tool call arguments. - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - @Nullable - public KernelArguments getArguments() { - return arguments; - } - - /** - * Get the tool call function. - * @return The tool call function. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public KernelFunction getFunction() { - return function; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java deleted file mode 100644 index 348d3bf12..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Represents a KernelHookEvent that is raised after a prompt is rendered. - */ -public class PromptRenderedEvent implements KernelHookEvent { - - private final KernelFunction function; - private final KernelArguments arguments; - private final String prompt; - - /** - * Creates a new instance of the {@link PromptRenderedEvent} class. - * - * @param function the function - * @param arguments the arguments - * @param prompt the prompt - */ - public PromptRenderedEvent( - KernelFunction function, - @Nullable KernelArguments arguments, - String prompt) { - this.function = function; - this.arguments = KernelArguments.builder().withVariables(arguments).build(); - this.prompt = prompt; - } - - /** - * Gets the function that was invoked. - * - * @return the function - */ - public KernelFunction getFunction() { - return function; - } - - /** - * Gets the arguments that were passed to the function. - * - * @return the arguments - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelArguments getArguments() { - return arguments; - } - - /** - * Gets the prompt that was rendered. - * - * @return the prompt - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public String getPrompt() { - return prompt; - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java deleted file mode 100644 index fe9c54459..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.hooks; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Represents a KernelHookEvent that is raised after a prompt is rendered. - */ -public class PromptRenderingEvent implements KernelHookEvent { - - private final KernelFunction function; - private final KernelArguments arguments; - - /** - * Creates a new instance of the {@link PromptRenderingEvent} class. - * - * @param function the function - * @param arguments the arguments - */ - public PromptRenderingEvent(KernelFunction function, - @Nullable KernelArguments arguments) { - this.function = function; - this.arguments = KernelArguments.builder().withVariables(arguments).build(); - } - - /** - * Gets the function that was invoked. - * - * @return the function - */ - public KernelFunction getFunction() { - return function; - } - - /** - * Gets the arguments that were passed to the function. - * - * @return the arguments - */ - @SuppressFBWarnings("EI_EXPOSE_REP") - public KernelArguments getArguments() { - return arguments; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/CollectionUtil.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/CollectionUtil.java deleted file mode 100644 index 1f95820e5..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/CollectionUtil.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -import java.util.List; -import javax.annotation.Nullable; - -public class CollectionUtil { - - @Nullable - public static T getLastOrNull( - @Nullable List collection) { - if (collection == null || collection.isEmpty()) { - return null; - } - - return collection.get(collection.size() - 1); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoader.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoader.java deleted file mode 100644 index 9bc9d661c..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoader.java +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.file.Files; -import java.text.MessageFormat; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class for loading resources from the classpath or filesystem. - */ -public class EmbeddedResourceLoader { - - private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedResourceLoader.class); - - /** - * Loads a file to a string from the classpath using getResourceAsStream - * - * @param fileName Filename to read - * @param clazz Class to use for classpath loading - * @return File content - * @throws FileNotFoundException Error in case the file doesn't exist - */ - public static String readFile(String fileName, Class clazz) throws FileNotFoundException { - return readFile(fileName, clazz, ResourceLocation.CLASSPATH); - } - - /** - * Loads a file to a string from the classpath, classpath root or filesystem - * - * @param fileName Filename to read - * @param clazz Class to use for classpath loading - * @param locations Locations to search for the file - * @return File content - * @throws FileNotFoundException Error in case the file doesn't exist - */ - public static String readFile(String fileName, @Nullable Class clazz, - ResourceLocation... locations) - throws FileNotFoundException { - - List locationsList = Arrays.stream(locations) - .collect(Collectors.toList()); - - Optional fileContents = locationsList.stream() - .map( - type -> { - switch (type) { - case CLASSPATH: - if (clazz == null) { - throw new SKException( - "Resource location CLASSPATH requires a class"); - } - return getResourceAsStream(fileName, clazz); - case CLASSPATH_ROOT: - try (InputStream inputStream = Thread.currentThread() - .getContextClassLoader() - .getResourceAsStream(fileName)) { - return readInputStream(fileName, inputStream); - } catch (IOException e) { - // IGNORE - } - break; - case FILESYSTEM: - return readFileFromFileSystem(fileName); - default: - } - return null; - }) - .filter(Objects::nonNull) - .findFirst(); - - if (fileContents.isPresent()) { - return fileContents.get(); - } - - throw new FileNotFoundException("Could not find file " + fileName); - } - - @Nullable - // visible for testing - static String getResourceAsStream(String fileName, Class clazz) { - try (InputStream inputStream = clazz.getResourceAsStream(fileName)) { - return readInputStream(fileName, inputStream); - } catch (Exception e) { - // IGNORE - } - return null; - } - - @Nullable - // visible for testing - static String readFileFromFileSystem(String fileName) { - File file = new File(fileName); - if (file.exists()) { - try (InputStream inputStream = Files.newInputStream(file.toPath())) { - return readInputStream(fileName, inputStream); - } catch (IOException e) { - // IGNORE - } - } - return null; - } - - @Nullable - // visible for testing - private static String readInputStream(String fileName, InputStream inputStream) - throws FileNotFoundException { - if (inputStream == null) { - throw new FileNotFoundException("File not found: " + fileName); - } - - try (BufferedReader bf = new BufferedReader( - new InputStreamReader(inputStream, java.nio.charset.StandardCharsets.UTF_8))) { - return bf.lines().collect(Collectors.joining("\n")); - } catch (IOException e) { - // IGNORE - LOGGER.trace( - MessageFormat.format(SemanticKernelResources.getString("failed.to.load.file.0"), - fileName), - e); - } - return null; - } - - /** - * Enum for specifying the location of the resource - */ - public enum ResourceLocation { - /** - * Load from the classpath - */ - CLASSPATH, - /** - * Load from the filesystem - */ - FILESYSTEM, - /** - * Load from the classpath root - */ - CLASSPATH_ROOT - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/ServiceLoadUtil.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/ServiceLoadUtil.java deleted file mode 100644 index fe4544dfe..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/ServiceLoadUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; -import java.util.function.Supplier; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is used for loading services that are not directly referenced in the code, but are - * instead loaded using the ServiceLoader pattern. - */ -public class ServiceLoadUtil { - - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceLoadUtil.class); - - private ServiceLoadUtil() { - } - - /** - * Finds a service loader for the given class and returns a supplier for it. - * - * @param clazz The class to find a service loader for. - * @param The type of the class to find a service loader for. - * @param alternativeClassName The name of the alternative class to load if the service loader - * is not found. - * @return A {@code java.util.function.Supplier} for the service loader. - */ - public static Supplier findServiceLoader(Class clazz, String alternativeClassName) { - List services = findAllServiceLoaders(clazz); - - T impl = null; - - if (!services.isEmpty()) { - impl = services.get(0); - } - - if (impl == null) { - try { - // Service loader not found, attempt to load the alternative class - Object instance = Class.forName(alternativeClassName).getDeclaredConstructor() - .newInstance(); - if (clazz.isInstance(instance)) { - impl = (T) instance; - } - } catch (ClassNotFoundException - | InvocationTargetException - | InstantiationException - | IllegalAccessException - | NoSuchMethodException - | RuntimeException e) { - LOGGER.error(String.format( - SemanticKernelResources.getString("unable.to.load.service.s"), clazz.getName()), - e); - } - - if (impl == null) { - throw new RuntimeException(String.format("Service not found: %s", clazz.getName())); - } - } - - try { - Constructor constructor = impl.getClass().getConstructor(); - - // Test that we can construct the builder - if (!clazz.isInstance(constructor.newInstance())) { - throw new RuntimeException( - "Builder creates instance of the wrong type: " + clazz.getName()); - } - - return () -> { - try { - return (T) constructor.newInstance(); - } catch (InstantiationException - | IllegalAccessException - | InvocationTargetException e) { - throw new RuntimeException(e); - } - }; - } catch (NoSuchMethodException e) { - throw new RuntimeException( - "Builder requires a no args constructor: " + clazz.getName()); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException("Builder is of wrong type: " + clazz.getName()); - } - } - - static List findAllServiceLoaders(Class clazz) { - List serviceLoaders = new ArrayList(); - - ServiceLoader factory = ServiceLoader.load(clazz); - Iterator iterator = factory.iterator(); - iterator.forEachRemaining(serviceLoaders::add); - - return serviceLoaders; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Todo.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Todo.java deleted file mode 100644 index fe7113b0b..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Todo.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -/** - * This is used as a placeholder for methods that are not yet implemented. - */ -public class Todo extends RuntimeException { - - /** - * Initializes a new instance of the {@link Todo} class. - */ - public Todo() { - super("TODO: Implement this method"); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Verify.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Verify.java deleted file mode 100644 index 6e6d002b3..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/Verify.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -import javax.annotation.Nullable; - -/** - * Provides methods for verifying the state of objects and strings in a consistent manner. - */ -public class Verify { - - /** - * Verifies that the given object is not {@code null}. - * - * @param object The object to verify. - */ - public static void notNull(Object object) { - assert object != null; - } - - /** - * Verifies that the given object is {@code null} or empty. - * - * @param s The String to verify. - * @return true if the object is {@code null} or empty; otherwise, false. - */ - public static boolean isNullOrEmpty(@Nullable String s) { - return s == null || s.isEmpty(); - } - - /** - * Verifies that the given object is {@code null} or contains only whitespace. - * - * @param s The String to verify. - * @return true if the object is {@code null} or whitespace; otherwise, false. - */ - public static boolean isNullOrWhiteSpace(String s) { - return s == null || s.matches("^\\w+$"); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatPromptParseVisitor.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatPromptParseVisitor.java deleted file mode 100644 index f7b3e0689..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatPromptParseVisitor.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.chatcompletion; - -import com.azure.core.util.BinaryData; -import javax.annotation.Nullable; - -public interface ChatPromptParseVisitor { - - ChatPromptParseVisitor addMessage(String role, String content); - - ChatPromptParseVisitor addFunction(String name, @Nullable String description, - @Nullable BinaryData parameters); - - boolean areMessagesEmpty(); - - ChatPromptParseVisitor fromRawPrompt(String rawPrompt); - - T get(); - - ChatPromptParseVisitor reset(); -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java deleted file mode 100644 index 8cc1cc972..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.chatcompletion; - -import com.azure.core.util.BinaryData; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import javax.annotation.Nullable; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ChatXMLPromptParser { - - private static final Logger LOGGER = LoggerFactory.getLogger(ChatXMLPromptParser.class); - - public static ChatPromptParseVisitor parse( - String rawPrompt, - ChatPromptParseVisitor chatPromptParseVisitor) { - List prompts = Arrays.asList( - rawPrompt, - "" + rawPrompt + ""); - - for (String prompt : prompts) { - try { - chatPromptParseVisitor = getChatRequestMessages(prompt, chatPromptParseVisitor); - chatPromptParseVisitor = getFunctionDefinitions(prompt, chatPromptParseVisitor); - - if (!chatPromptParseVisitor.areMessagesEmpty()) { - return chatPromptParseVisitor; - } - } catch (SKException e) { - //ignore - chatPromptParseVisitor = chatPromptParseVisitor.reset(); - } - } - - return chatPromptParseVisitor.fromRawPrompt(rawPrompt); - } - - private static ChatPromptParseVisitor getChatRequestMessages(String prompt, - ChatPromptParseVisitor chatPromptParseVisitor) { - - // TODO: XML parsing should be done as a chain of XMLEvent handlers. - // If one handler does not recognize the element, it should pass it to the next handler. - // In this way, we can avoid parsing the whole prompt twice and easily extend the parsing logic. - - try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) { - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLEventReader reader = factory.createXMLEventReader(is); - while (reader.hasNext()) { - XMLEvent event = reader.nextEvent(); - if (event.isStartElement()) { - String name = getElementName(event); - if (name.equals("message")) { - String role = getAttributeValue(event, "role"); - String content = reader.getElementText(); - chatPromptParseVisitor = chatPromptParseVisitor.addMessage(role, content); - } - } - } - } catch (IOException | XMLStreamException | IllegalArgumentException e) { - throw new SKException("Failed to parse messages"); - } - return chatPromptParseVisitor; - } - - private static class FunctionDefinition { - - private final String name; - private final String description; - @Nullable - private BinaryData parameters; - - public FunctionDefinition(String name, String description) { - this.name = name; - this.description = description; - this.parameters = null; - } - - public void setParameters(BinaryData binaryData) { - this.parameters = binaryData; - } - } - - private static ChatPromptParseVisitor getFunctionDefinitions(String prompt, - ChatPromptParseVisitor chatPromptParseVisitor) { - // TODO: XML parsing should be done as a chain of XMLEvent handlers. See previous remark. - // - // ... - // - - try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) { - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLEventReader reader = factory.createXMLEventReader(is); - FunctionDefinition functionDefinition = null; - Map parameters = new HashMap<>(); - List requiredParameters = new ArrayList<>(); - while (reader.hasNext()) { - XMLEvent event = reader.nextEvent(); - if (event.isStartElement()) { - String elementName = getElementName(event); - if (elementName.equals("function")) { - assert functionDefinition == null; - assert parameters.isEmpty(); - assert requiredParameters.isEmpty(); - String pluginName = getAttributeValue(event, "pluginName"); - String name = getAttributeValue(event, "name"); - String description = getAttributeValue(event, "description"); - // name has to match '^[a-zA-Z0-9_-]{1,64}$' - functionDefinition = new FunctionDefinition( - ToolCallBehavior.formFullFunctionName(pluginName, name), - description); - } else if (elementName.equals("parameter")) { - String name = getAttributeValue(event, "name"); - String type = getAttributeValue(event, "type").toLowerCase(Locale.ROOT); - String description = getAttributeValue(event, "description"); - parameters.put(name, - String.format("{\"type\": \"%s\", \"description\": \"%s\"}", - "string", - description)); - - String isRequired = getAttributeValue(event, "isRequired"); - if (Boolean.parseBoolean(isRequired)) { - requiredParameters.add(name); - } - } - } else if (event.isEndElement()) { - String elementName = getElementName(event); - if (elementName.equals("function")) { - // Example JSON Schema: - // { - // "type": "function", - // "function": { - // "name": "get_current_weather", - // "description": "Get the current weather in a given location", - // "parameters": { - // "type": "object", - // "properties": { - // "location": { - // "type": "string", - // "description": "The city and state, e.g. San Francisco, CA", - // }, - // "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, - // }, - // "required": ["location"], - // }, - // }, - //} - if (functionDefinition == null) { - throw new SKException("Failed to parse function definition"); - } - if (!parameters.isEmpty()) { - StringBuilder sb = new StringBuilder( - "{\"type\": \"object\", \"properties\": {"); - parameters.forEach((name, value) -> { - // make "param": {"type": "string", "description": "desc"}, - sb.append(String.format("\"%s\": %s,", name, value)); - }); - // strip off trailing comma and close the properties object - sb.replace(sb.length() - 1, sb.length(), "}"); - if (!requiredParameters.isEmpty()) { - sb.append(", \"required\": ["); - requiredParameters.forEach(name -> { - sb.append(String.format("\"%s\",", name)); - }); - // strip off trailing comma and close the required array - sb.replace(sb.length() - 1, sb.length(), "]"); - } - // close the object - sb.append("}"); - //System.out.println(sb.toString()); - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonNode = objectMapper.readTree(sb.toString()); - BinaryData binaryData = BinaryData.fromObject(jsonNode); - functionDefinition.setParameters(binaryData); - } - chatPromptParseVisitor = chatPromptParseVisitor.addFunction( - functionDefinition.name, - functionDefinition.description, - functionDefinition.parameters); - functionDefinition = null; - parameters.clear(); - requiredParameters.clear(); - } - } - } - } catch (IOException | XMLStreamException | IllegalArgumentException e) { - LOGGER.error(SemanticKernelResources.getString("error.parsing.prompt"), e); - } - return chatPromptParseVisitor; - } - - private static String getElementName(XMLEvent xmlEvent) { - if (xmlEvent.isStartElement()) { - return xmlEvent.asStartElement().getName().getLocalPart(); - } else if (xmlEvent.isEndElement()) { - return xmlEvent.asEndElement().getName().getLocalPart(); - } - // TODO: programmer's error - log at debug - return ""; - } - - private static String getAttributeValue(XMLEvent xmlEvent, String attributeName) { - if (xmlEvent.isStartElement()) { - StartElement element = xmlEvent.asStartElement(); - Attribute attribute = element.getAttributeByName(QName.valueOf(attributeName)); - return attribute != null ? attribute.getValue() : ""; - } - // TODO: programmer's error - log at debug - return ""; - } -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java deleted file mode 100644 index 9fa465ed9..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.telemetry; - -import com.azure.ai.openai.models.ChatCompletions; -import com.azure.ai.openai.models.CompletionsUsage; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Scope; -import java.util.function.Function; -import javax.annotation.Nullable; -import reactor.util.context.Context; -import reactor.util.context.ContextView; - -public class ChatCompletionSpan extends SemanticKernelTelemetrySpan { - - public ChatCompletionSpan( - Span span, - Function reactorContextModifier, - Scope spanScope, - Scope contextScope) { - super(span, reactorContextModifier, spanScope, contextScope); - } - - public static ChatCompletionSpan startChatCompletionSpan( - SemanticKernelTelemetry telemetry, - ContextView contextView, - @Nullable String modelName, - String modelProvider, - @Nullable Integer maxTokens, - @Nullable Double temperature, - @Nullable Double topP) { - return startCompletionSpan( - telemetry, - contextView, - "chat.completions", - modelName, - modelProvider, - maxTokens, - temperature, topP); - } - - public ChatCompletionSpan startTextCompletionSpan( - SemanticKernelTelemetry telemetry, - ContextView contextView, - @Nullable String modelName, - String modelProvider, - @Nullable Integer maxTokens, - @Nullable Double temperature, - @Nullable Double topP) { - return startCompletionSpan( - telemetry, - contextView, - "text.completions", - modelName, - modelProvider, - maxTokens, - temperature, topP); - } - - public static ChatCompletionSpan startCompletionSpan( - SemanticKernelTelemetry telemetry, - ContextView contextView, - String operationName, - @Nullable String modelName, - String modelProvider, - @Nullable Integer maxTokens, - @Nullable Double temperature, - @Nullable Double topP) { - if (modelName == null) { - modelName = "unknown"; - } - - SpanBuilder builder = telemetry.spanBuilder(operationName + " " + modelName) - .setSpanKind(SpanKind.CLIENT) - .setAttribute("gen_ai.request.model", modelName) - .setAttribute("gen_ai.operation.name", operationName) - .setAttribute("gen_ai.system", modelProvider); - - if (maxTokens != null) { - builder.setAttribute("gen_ai.request.max_tokens", maxTokens); - } - if (temperature != null) { - builder.setAttribute("gen_ai.request.temperature", temperature); - } - if (topP != null) { - builder.setAttribute("gen_ai.request.top_p", topP); - } - - Span span = builder.startSpan(); - - return build( - span, - contextView, - (contextModifier, spanScope, contextScope) -> new ChatCompletionSpan( - span, - contextModifier, - spanScope, - contextScope)); - } - - public void endSpanWithUsage(ChatCompletions chatCompletions) { - CompletionsUsage usage = chatCompletions.getUsage(); - getSpan().setStatus(StatusCode.OK); - getSpan() - .setAttribute("gen_ai.usage.output_tokens", usage.getCompletionTokens()); - getSpan().setAttribute("gen_ai.usage.input_tokens", usage.getPromptTokens()); - close(); - } - - public void endSpanWithError(Throwable throwable) { - getSpan().setStatus(StatusCode.ERROR, throwable.getMessage()); - close(); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java deleted file mode 100644 index 72cc02609..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.telemetry; - -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Scope; -import java.util.function.Function; -import reactor.util.context.Context; -import reactor.util.context.ContextView; - -public class FunctionSpan extends SemanticKernelTelemetrySpan { - - public FunctionSpan( - Span span, - Function reactorContextModifier, - Scope spanScope, - Scope contextScope) { - super(span, reactorContextModifier, spanScope, contextScope); - } - - public static FunctionSpan build( - SemanticKernelTelemetry telemetry, - ContextView contextView, - String pluginName, - String name, - KernelArguments arguments) { - - SpanBuilder builder = telemetry.spanBuilder( - String.format("function_invocation %s-%s", pluginName, name)) - .setSpanKind(SpanKind.INTERNAL) - .setAttribute("semantic_kernel.function.invocation.name", name) - .setAttribute("semantic_kernel.function.invocation.plugin_name", pluginName); - - Span span = builder.startSpan(); - - return build( - span, - contextView, - (contextModifier, spanScope, contextScope) -> new FunctionSpan( - span, - contextModifier, - spanScope, - contextScope)); - } - - public void onFunctionSuccess(FunctionResult result) { - try { - getSpan().setStatus(StatusCode.OK); - } finally { - close(); - } - } - - public void onFunctionError(Throwable error) { - try { - getSpan().setStatus(StatusCode.ERROR, error.getMessage()); - getSpan().recordException(error); - } finally { - close(); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetry.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetry.java deleted file mode 100644 index 4121881d8..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetry.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.telemetry; - -import com.microsoft.semantickernel.orchestration.InvocationContext; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.api.trace.Tracer; -import javax.annotation.Nullable; - -public class SemanticKernelTelemetry { - - public static final String OPEN_AI_PROVIDER = "openai"; - - private final Tracer tracer; - - @Nullable - private final SpanContext spanContext; - - public SemanticKernelTelemetry( - Tracer tracer, - @Nullable SpanContext spanContext) { - - this.tracer = tracer; - this.spanContext = spanContext; - } - - public SemanticKernelTelemetry() { - this( - GlobalOpenTelemetry.getTracer("SemanticKernel"), - null); - } - - public static SemanticKernelTelemetry getTelemetry( - @Nullable InvocationContext invocationContext) { - if (invocationContext != null) { - return invocationContext.getTelemetry(); - } - return new SemanticKernelTelemetry(); - } - - private Tracer getTracer() { - return tracer; - } - - public SpanBuilder spanBuilder(String operationName) { - SpanBuilder sb = tracer.spanBuilder(operationName); - - if (spanContext != null) { - sb.addLink(spanContext); - } - return sb; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetrySpan.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetrySpan.java deleted file mode 100644 index 2ef6413ce..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/SemanticKernelTelemetrySpan.java +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.telemetry; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.reactor.v3_1.ContextPropagationOperator; -import java.io.Closeable; -import java.time.Duration; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; -import org.slf4j.Logger; -import reactor.core.Disposable; -import reactor.core.publisher.Mono; -import reactor.util.context.ContextView; - -public abstract class SemanticKernelTelemetrySpan implements Closeable { - - private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger( - SemanticKernelTelemetrySpan.class); - - private static final long SPAN_TIMEOUT_MS = Long.parseLong((String) System.getProperties() - .getOrDefault("semantickernel.telemetry.span_timeout", "120000")); - - private final Span span; - private final Function reactorContextModifier; - private final Scope spanScope; - private final Scope contextScope; - private final AtomicBoolean closed = new AtomicBoolean(false); - - // Timeout to close the span if it was not closed within the specified time to avoid memory leaks - private final Disposable watchdog; - - // This is a finalizer guardian to ensure that the span is closed if it was not closed explicitly - @SuppressWarnings("unused") - private final Object finalizerGuardian = new Object() { - @Override - protected void finalize() { - if (closed.get() == false) { - LOGGER.warn("Span was not closed"); - close(); - } - } - }; - - public SemanticKernelTelemetrySpan(Span span, - Function reactorContextModifier, - Scope spanScope, Scope contextScope) { - this.span = span; - this.reactorContextModifier = reactorContextModifier; - this.spanScope = spanScope; - this.contextScope = contextScope; - - watchdog = Mono.just(1) - .delay(Duration.ofMillis(SPAN_TIMEOUT_MS)) - .subscribe(i -> { - if (closed.get() == false) { - LOGGER.warn("Span was not closed, timing out"); - close(); - } - }); - } - - public interface SpanConstructor { - - public T build( - Function contextModifier, - Scope spanScope, - Scope contextScope); - } - - // Does need to be closed but as we are doing this in a reactive app, cant enforce the try with resources - @SuppressWarnings("MustBeClosedChecker") - public static T build( - Span span, - ContextView contextView, - SpanConstructor builder) { - LOGGER.trace("Starting Span: {}", span); - - Context currentOtelContext = ContextPropagationOperator - .getOpenTelemetryContextFromContextView( - contextView, - Context.current()); - - Context otelContext = span.storeInContext(currentOtelContext); - Scope contextScope = otelContext.makeCurrent(); - Scope spanScope = span.makeCurrent(); - - Function reactorContextModifier = ctx -> { - return ContextPropagationOperator.storeOpenTelemetryContext(ctx, otelContext); - }; - - return builder.build(reactorContextModifier, spanScope, contextScope); - } - - public Function getReactorContextModifier() { - return reactorContextModifier; - } - - public void close() { - if (closed.compareAndSet(false, true)) { - LOGGER.trace("Closing span: {}", span); - if (span.isRecording()) { - try { - span.end(); - } catch (Exception e) { - LOGGER.error("Error closing span", e); - } - } - if (contextScope != null) { - try { - contextScope.close(); - } catch (Exception e) { - LOGGER.error("Error closing context scope", e); - } - } - if (spanScope != null) { - try { - spanScope.close(); - } catch (Exception e) { - LOGGER.error("Error closing span scope", e); - } - } - watchdog.dispose(); - } - } - - public Span getSpan() { - return span; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/CodeTokenizer.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/CodeTokenizer.java deleted file mode 100644 index 3fad53bfc..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/CodeTokenizer.java +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.Verify; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Block; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.FunctionIdBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.NamedArgBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Symbols; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.ValBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.VarBlock; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Simple tokenizer used for default SK template code language. - *

- * BNF parsed by TemplateTokenizer: [template] ::= "" | [block] | [block] [template] [block] - * ::= [sk-block] | [text-block] [sk-block] ::= "{{" [variable] "}}" | "{{" [value] "}}" | - * "{{" [function-call] "}}" [text-block] ::= [any-char] | [any-char] [text-block] [any-char] - * ::= any char - *

- * BNF parsed by CodeTokenizer: [template] ::= "" | [variable] " " [template] | [value] " " - * [template] | [function-call] " [variable] ::= "$" [valid-name] [value] ::= "'" - * [text] "'" | '"' [text] '"' [function-call] ::= [function-id] | [function-id] [parameter] - * [parameter] ::= [variable] | [value] - *

- * BNF parsed by dedicated blocks [function-id] ::= [valid-name] | [valid-name] "." [valid-name] - * [valid-name] ::= [valid-symbol] | [valid-symbol] [valid-name] [valid-symbol] ::= [letter] | - * [digit] | "_" [letter] ::= "a" | "b" ... | "z" | "A" | "B" ... | "Z" [digit] ::= - * "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" - */ -public class CodeTokenizer { - - /** - * Initializes a new instance of the {@link CodeTokenizer} class. - */ - public CodeTokenizer() { - } - - private static boolean isVarPrefix(char c) { - return (c == Symbols.VarPrefix); - } - - private static boolean IsBlankSpace(char c) { - return Character.isWhitespace(c); - } - - private static boolean isQuote(char c) { - return c == Symbols.DblQuote || c == Symbols.SglQuote; - } - - private static boolean CanBeEscaped(char c) { - return c == Symbols.DblQuote || c == Symbols.SglQuote || c == Symbols.EscapeChar; - } - - @SuppressWarnings("NullAway") - @Nullable - private static NamedArgBlock getNamedArg(String tokenContent) { - - String name = NamedArgBlock.tryGetName(tokenContent); - String value = NamedArgBlock.tryGetValue(tokenContent); - - if (Verify.isNullOrEmpty(name) || Verify.isNullOrEmpty(value)) { - return null; - } - NamedArgBlock block = new NamedArgBlock(tokenContent, name, value); - if (block.isValid()) { - return block; - } - - return null; - } - - /** - * Tokenize a code block, without checking for syntax errors - * - * @param text Text to parse - * @return A list of blocks - */ - public List tokenize(String text) { - if (text == null) { - return new ArrayList<>(); - } - - // Remove spaces, which are ignored anyway - text = text.trim(); - - // Render NULL to "" - if (text.isEmpty()) { - return Collections.unmodifiableList(new ArrayList<>()); - } - - // Track what type of token we're reading - TokenTypes currentTokenType = TokenTypes.None; - - // Track the content of the current token - StringBuilder currentTokenContent = new StringBuilder(); - - char textValueDelimiter = '\0'; - - List blocks = new ArrayList<>(); - char nextChar = text.charAt(0); - - // Tokens must be separated by spaces, track their presence - boolean spaceSeparatorFound = false; - - // Named args may contain string values that contain spaces. These are used - // to determine when a space occurs between quotes. - boolean namedArgSeparatorFound = false; - char namedArgValuePrefix = '\0'; - - // 1 char only edge case - if (text.length() == 1) { - switch (nextChar) { - case Symbols.VarPrefix: - blocks.add(new VarBlock(text)); - break; - - case Symbols.DblQuote: - case Symbols.SglQuote: - blocks.add(new ValBlock(text)); - break; - - default: - blocks.add(new FunctionIdBlock(text)); - break; - } - - return blocks; - } - - boolean skipNextChar = false; - for (int nextCharCursor = 1; nextCharCursor < text.length(); nextCharCursor++) { - char currentChar = nextChar; - nextChar = text.charAt(nextCharCursor); - - if (skipNextChar) { - skipNextChar = false; - continue; - } - - // First char is easy - if (nextCharCursor == 1) { - if (isVarPrefix(currentChar)) { - currentTokenType = TokenTypes.Variable; - } else if (isQuote(currentChar)) { - currentTokenType = TokenTypes.Value; - textValueDelimiter = currentChar; - } else { - // A function Id starts here - currentTokenType = TokenTypes.FunctionId; - } - - currentTokenContent.append(currentChar); - continue; - } - - // While reading a values between quotes - if (currentTokenType == TokenTypes.Value - || (currentTokenType == TokenTypes.NamedArg && isQuote(namedArgValuePrefix))) { - // If the current char is escaping the next special char: - // - skip the current char (escape char) - // - add the next (special char) - // - jump to the one after (to handle "\\" properly) - if (currentChar == Symbols.EscapeChar && CanBeEscaped(nextChar)) { - currentTokenContent.append(nextChar); - skipNextChar = true; - continue; - } - - currentTokenContent.append(currentChar); - - // When we reach the end of the value - if (currentChar == textValueDelimiter) { - blocks.add(new ValBlock(currentTokenContent.toString())); - currentTokenContent = new StringBuilder(); - currentTokenType = TokenTypes.None; - spaceSeparatorFound = false; - } else if (currentChar == namedArgValuePrefix - && currentTokenType == TokenTypes.NamedArg) { - blocks.add(NamedArgBlock.from(currentTokenContent.toString())); - currentTokenContent = new StringBuilder(); - currentTokenType = TokenTypes.None; - spaceSeparatorFound = false; - namedArgSeparatorFound = false; - namedArgValuePrefix = '\0'; - } - - continue; - } - - // If we're not between quotes, a space signals the end of the current token - // Note: there might be multiple consecutive spaces - if (IsBlankSpace(currentChar)) { - if (currentTokenType == TokenTypes.Variable) { - blocks.add(new VarBlock(currentTokenContent.toString())); - currentTokenContent = new StringBuilder(); - } else if (currentTokenType == TokenTypes.FunctionId) { - String tokenContent = currentTokenContent.toString(); - // This isn't an expected block at this point but the TemplateTokenizer should throw an error when - // a named arg is used without a function call - - NamedArgBlock namedArg = getNamedArg(tokenContent); - - if (namedArg != null) { - blocks.add(namedArg); - } else { - blocks.add(new FunctionIdBlock(tokenContent)); - } - currentTokenContent = new StringBuilder(); - currentTokenType = TokenTypes.None; - } else if (currentTokenType == TokenTypes.NamedArg && namedArgSeparatorFound - && namedArgValuePrefix != 0) { - blocks.add( - NamedArgBlock.from(currentTokenContent.toString())); - currentTokenContent = new StringBuilder(); - namedArgSeparatorFound = false; - namedArgValuePrefix = '\0'; - currentTokenType = TokenTypes.None; - } - spaceSeparatorFound = true; - currentTokenType = TokenTypes.None; - - continue; - } - - // If reading a named argument and either the '=' or the value prefix ($, ', or ") haven't been found - if (currentTokenType == TokenTypes.NamedArg && (!namedArgSeparatorFound - || namedArgValuePrefix == 0)) { - if (!namedArgSeparatorFound) { - if (currentChar == Symbols.NamedArgBlockSeparator) { - namedArgSeparatorFound = true; - } - } else { - namedArgValuePrefix = currentChar; - if (!isQuote(namedArgValuePrefix) && namedArgValuePrefix != Symbols.VarPrefix) { - throw new SKException( - "Named argument values need to be prefixed with a quote or " - + Symbols.VarPrefix); - } - } - currentTokenContent.append(currentChar); - continue; - } - - // If we're not inside a quoted value and we're not processing a space - currentTokenContent.append(currentChar); - - if (currentTokenType == TokenTypes.None) { - if (!spaceSeparatorFound) { - throw new TemplateException( - TemplateException.ErrorCodes.SYNTAX_ERROR, - "Tokens must be separated by one space least"); - } - - if (isQuote(currentChar)) { - // A quoted value starts here - currentTokenType = TokenTypes.Value; - textValueDelimiter = currentChar; - } else if (isVarPrefix(currentChar)) { - // A variable starts here - currentTokenType = TokenTypes.Variable; - } else if (blocks.isEmpty()) { - // A function Id starts here - currentTokenType = TokenTypes.FunctionId; - } else { - // A named arg starts here - currentTokenType = TokenTypes.NamedArg; - } - } - } - - // Capture last token - currentTokenContent.append(nextChar); - switch (currentTokenType) { - case Value: - blocks.add(new ValBlock(currentTokenContent.toString())); - break; - - case Variable: - blocks.add(new VarBlock(currentTokenContent.toString())); - break; - - case FunctionId: - NamedArgBlock namedArg = getNamedArg(currentTokenContent.toString()); - - // This isn't an expected block at this point but the TemplateTokenizer should throw an error when - // a named arg is used without a function call - if (namedArg != null) { - blocks.add(namedArg); - } else { - blocks.add(new FunctionIdBlock(currentTokenContent.toString())); - } - - break; - case NamedArg: - blocks.add(NamedArgBlock.from(currentTokenContent.toString())); - break; - - case None: - throw new TemplateException( - TemplateException.ErrorCodes.SYNTAX_ERROR, - "Tokens must be separated by one space least"); - } - - return blocks; - } - - private enum TokenTypes { - None(0), Value(1), Variable(2), FunctionId(3), NamedArg(4); - - TokenTypes(int i) { - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java deleted file mode 100644 index 15b80a662..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.Verify; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Block; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.BlockTypes; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.CodeRendering; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.NamedArgBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.TextRendering; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.VarBlock; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException.ErrorCodes; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * The default prompt template. - */ -public class DefaultPromptTemplate implements PromptTemplate { - - private final PromptTemplateConfig promptTemplateConfig; - private final List blocks; - - /** - * Create a new prompt template. - * - * @param promptTemplateConfig The prompt template configuration. - */ - private DefaultPromptTemplate( - @Nonnull PromptTemplateConfig promptTemplateConfig, - @Nonnull List blocks) { - this.promptTemplateConfig = promptTemplateConfig; - this.blocks = Collections.unmodifiableList(blocks); - } - - /** - * Build a new prompt template from the given prompt template configuration. - * - * @param promptTemplateConfig The prompt template configuration. - * @return The new prompt template. - */ - public static DefaultPromptTemplate build(@Nonnull PromptTemplateConfig promptTemplateConfig) { - - List blocks = extractBlocks(promptTemplateConfig); - promptTemplateConfig = addMissingInputVariables(promptTemplateConfig, blocks); - - return new DefaultPromptTemplate(promptTemplateConfig, blocks); - } - - /* - * Given a prompt template string, extract all the blocks (text, variables, function calls) - * - * @return A list of all the blocks, ie the template tokenized in text, variables and function - * calls - */ - private static List extractBlocks(PromptTemplateConfig promptTemplateConfig) { - String templateText = promptTemplateConfig.getTemplate(); - - if (templateText == null) { - throw new SKException( - String.format("No prompt template was provided for the prompt %s.", - promptTemplateConfig.getName())); - } - - List blocks = new TemplateTokenizer().tokenize(templateText); - - Optional invalid = blocks - .stream() - .filter(block -> !block.isValid()) - .findFirst(); - - if (invalid.isPresent()) { - throw new TemplateException(ErrorCodes.SYNTAX_ERROR, - "Invalid block: " + invalid.get().getContent()); - } - - return blocks; - } - - /** - * Augments the prompt template with any variables not already contained there but that are - * referenced in the prompt template. - * - * @param blocks The blocks to search for input variables. - * @return The augmented prompt template. - */ - @SuppressWarnings("NullAway") - private static PromptTemplateConfig addMissingInputVariables( - PromptTemplateConfig promptTemplateConfig, List blocks) { - // Add all of the existing input variables to our known set. We'll avoid adding any - // dynamically discovered input variables with the same name. - Set seen = new HashSet<>(); - - seen.addAll( - promptTemplateConfig - .getInputVariables() - .stream() - .map(InputVariable::getName) - .collect(Collectors.toList())); - - PromptTemplateConfig.Builder promptTemplateConfigBuilder = promptTemplateConfig.copy(); - - blocks.forEach(block -> { - String name = null; - if (block.getType() == BlockTypes.VARIABLE) { - name = ((VarBlock) block).getName(); - } else if (block.getType() == BlockTypes.NAMED_ARG) { - VarBlock blockName = ((NamedArgBlock) block).getVarBlock(); - name = blockName == null ? null : blockName.getName(); - } - - if (!Verify.isNullOrEmpty(name) && !seen.contains(name)) { - seen.add(name); - promptTemplateConfigBuilder.addInputVariable(new InputVariable(name)); - } - }); - - return promptTemplateConfigBuilder.build(); - } - - @Override - public Mono renderAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable InvocationContext context) { - - ContextVariableTypes types; - - if (context != null) { - types = context.getContextVariableTypes(); - } else { - types = new ContextVariableTypes(); - } - return Flux - .fromIterable(blocks) - .concatMap(block -> { - if (block instanceof TextRendering) { - return Mono.just( - ((TextRendering) block).render(types, arguments)); - } else if (block instanceof CodeRendering) { - return ((CodeRendering) block).renderCodeAsync(kernel, arguments, context); - } else { - return Mono.error(new TemplateException(ErrorCodes.UNEXPECTED_BLOCK_TYPE)); - } - }) - .reduce("", (a, b) -> { - return a + b; - }); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/TemplateTokenizer.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/TemplateTokenizer.java deleted file mode 100644 index d0a165388..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/TemplateTokenizer.java +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer; - -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Block; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.CodeBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Symbols; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.TextBlock; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Simple tokenizer used for default SK template language. - *

- * BNF parsed by TemplateTokenizer: [template] ::= "" | [block] | [block] [template] [block] - * ::= [sk-block] | [text-block] [sk-block] ::= "{{" [variable] "}}" | "{{" [value] "}}" | - * "{{" [function-call] "}}" [text-block] ::= [any-char] | [any-char] [text-block] [any-char] - * ::= any char - *

- * BNF parsed by CodeTokenizer: [template] ::= "" | [variable] " " [template] | [value] " " - * [template] | [function-call] " - *

- * [variable] ::= "$" [valid-name] [value] ::= "'" [text] "'" | '"' [text] '"' - * [function-call] ::= [function-id] | [function-id] [parameter] [parameter] ::= [variable] | - * [value] - *

- * BNF parsed by dedicated blocks [function-id] ::= [valid-name] | [valid-name] "." [valid-name] - * [valid-name] ::= [valid-symbol] | [valid-symbol] [valid-name] [valid-symbol] ::= [letter] | - * [digit] | "_" [letter] ::= "a" | "b" ... | "z" | "A" | "B" ... | "Z" [digit] ::= - * "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" - */ -public class TemplateTokenizer { - - /* - * #region private - * ================================================================================ - * - * private readonly ILogger _log; - */ - private final CodeTokenizer codeTokenizer = new CodeTokenizer(); - - private static String subStr(String text, int startIndex, int stopIndex) { - return text.substring(startIndex, stopIndex); - } - - private static boolean isQuote(char c) { - return c == Symbols.DblQuote || c == Symbols.SglQuote; - } - - private static boolean canBeEscaped(char c) { - return c == Symbols.DblQuote || c == Symbols.SglQuote || c == Symbols.EscapeChar; - } - - /** - * Extract blocks from the given text - * - * @param text Text to parse - * @return List of blocks found in the text - */ - public List tokenize(String text) { - // An empty block consists of 4 chars: "{{}}" - int EMPTY_CODE_BLOCK_LENGTH = 4; - // A block shorter than 5 chars is either empty or invalid, e.g. "{{ }}" and "{{$}}" - int MIN_CODE_BLOCK_LENGTH = EMPTY_CODE_BLOCK_LENGTH + 1; - - // Render NULL to "" - if (text == null || text.isEmpty()) { - return Collections.singletonList(new TextBlock("")); - } - - // If the template is "empty" return the content as a text block - if (text.length() < MIN_CODE_BLOCK_LENGTH) { - return Collections.singletonList(new TextBlock(text)); - } - - List blocks = new ArrayList<>(); - - int endOfLastBlock = 0; - - int blockStartPos = 0; - boolean blockStartFound = false; - - boolean insideTextValue = false; - char textValueDelimiter = '\0'; - - boolean skipNextChar = false; - - char nextChar = text.charAt(0); - for (int nextCharCursor = 1; nextCharCursor < text.length(); nextCharCursor++) { - int currentCharPos = nextCharCursor - 1; - int cursor = nextCharCursor; - char currentChar = nextChar; - nextChar = text.charAt(nextCharCursor); - - if (skipNextChar) { - skipNextChar = false; - continue; - } - - // When "{{" is found outside a value - // Note: "{{ {{x}}" => ["{{ ", "{{x}}"] - if (!insideTextValue - && currentChar == Symbols.BlockStarter - && nextChar == Symbols.BlockStarter) { - // A block starts at the first "{" - blockStartPos = currentCharPos; - blockStartFound = true; - } - - // After having found '{{' - if (blockStartFound) { - // While inside a text value, when the end quote is found - if (insideTextValue) { - if (currentChar == Symbols.EscapeChar && canBeEscaped(nextChar)) { - skipNextChar = true; - continue; - } - - if (currentChar == textValueDelimiter) { - insideTextValue = false; - } - } else { - // A value starts here - if (isQuote(currentChar)) { - insideTextValue = true; - textValueDelimiter = currentChar; - } - // If the block ends here - else if (currentChar == Symbols.BlockEnder && nextChar == Symbols.BlockEnder) { - // If there is plain text between the current var/val/code block and the - // previous one, capture that as a TextBlock - if (blockStartPos > endOfLastBlock) { - blocks.add(new TextBlock(text, endOfLastBlock, blockStartPos)); - } - - // Extract raw block - String contentWithDelimiters = subStr(text, blockStartPos, cursor + 1); - - // Remove "{{" and "}}" delimiters and trim empty chars - String contentWithoutDelimiters = contentWithDelimiters - .substring(2, contentWithDelimiters.length() - 2) - .trim(); - - if (contentWithoutDelimiters.isEmpty()) { - // If what is left is empty, consider the raw block a Text Block - blocks.add(new TextBlock(contentWithDelimiters)); - } else { - List codeBlocks = this.codeTokenizer - .tokenize(contentWithoutDelimiters); - - switch (codeBlocks.get(0).getType()) { - case VARIABLE: - if (codeBlocks.size() > 1) { - throw new TemplateException( - TemplateException.ErrorCodes.SYNTAX_ERROR, - "Invalid token detected after the variable: " - + contentWithoutDelimiters); - } - - blocks.add(codeBlocks.get(0)); - break; - - case VALUE: - if (codeBlocks.size() > 1) { - throw new TemplateException( - TemplateException.ErrorCodes.SYNTAX_ERROR, - "Invalid token detected after the value: " - + contentWithoutDelimiters); - } - - blocks.add(codeBlocks.get(0)); - break; - - case FUNCTION_ID: - blocks.add(new CodeBlock(codeBlocks, contentWithoutDelimiters)); - break; - - case CODE: - case TEXT: - case UNDEFINED: - default: - throw new TemplateException( - TemplateException.ErrorCodes.UNEXPECTED_BLOCK_TYPE, - "Code tokenizer returned an incorrect first token type " - + codeBlocks.get(0).getType()); - } - } - - endOfLastBlock = cursor + 1; - blockStartFound = false; - } - } - } - } - - // If there is something left after the last block, capture it as a TextBlock - if (endOfLastBlock < text.length()) { - blocks.add(new TextBlock(text, endOfLastBlock, text.length())); - } - - return Collections.unmodifiableList(blocks); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Block.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Block.java deleted file mode 100644 index a457270c2..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Block.java +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import javax.annotation.Nullable; - -/** - * Base class for blocks parsed from a prompt template - */ -public abstract class Block { - - private final String content; - private final BlockTypes type; - - /** - * Base constructor - * - * @param content Block content - * @param type Block type - */ - public Block( - @Nullable String content, - BlockTypes type) { - if (content == null) { - content = ""; - } - - this.content = content; - this.type = type; - } - - /** - * Get the block content - * - * @return Block content - */ - public String getContent() { - return content; - } - - /** - * Check if the block content is valid. - * - * @return True if the block content is valid - */ - public abstract boolean isValid(); - - /** - * Get the block type - * - * @return Block type - */ - public BlockTypes getType() { - return type; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/BlockTypes.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/BlockTypes.java deleted file mode 100644 index fa3ba80bc..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/BlockTypes.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -/** - * Block types - */ -public enum BlockTypes { - /** - * Undefined block type - */ - UNDEFINED, - /** - * Text block type - */ - TEXT, - /** - * Code block type - */ - CODE, - /** - * Variable block type - */ - VARIABLE, - /** - * Value block type - */ - VALUE, - /** - * Function block type - */ - FUNCTION_ID, - /** - * Named argument block type - */ - NAMED_ARG; -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java deleted file mode 100644 index cd6fffaad..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException.ErrorCodes; -import java.text.MessageFormat; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -/** - * Represents a code block. - */ -public final class CodeBlock extends Block implements CodeRendering { - - private static final Logger LOGGER = LoggerFactory.getLogger(CodeBlock.class); - private final List tokens; - - /** - * Initializes a new instance of the {@link CodeBlock} class. - * - * @param tokens The tokens. - * @param content The content. - */ - public CodeBlock(List tokens, String content) { - super(content, BlockTypes.CODE); - this.tokens = Collections.unmodifiableList(tokens); - } - - @Override - public boolean isValid() { - Optional invalid = tokens.stream().filter(token -> !token.isValid()).findFirst(); - if (invalid.isPresent()) { - LOGGER.error(MessageFormat.format(SemanticKernelResources.getString("invalid.block.0"), - invalid.get().getContent())); - return false; - } - - if (!this.tokens.isEmpty() && this.tokens.get(0).getType() == BlockTypes.NAMED_ARG) { - LOGGER.error(SemanticKernelResources.getString( - "unexpected.named.argument.found.expected.function.name.first")); - return false; - } - - if (this.tokens.size() > 1 && !this.isValidFunctionCall()) { - return false; - } - - return true; - } - - private boolean isValidFunctionCall() { - if (this.tokens.get(0).getType() != BlockTypes.FUNCTION_ID) { - LOGGER.error(MessageFormat.format( - SemanticKernelResources.getString("unexpected.second.token.found.0"), - tokens.get(1).getContent())); - return false; - } - - if (this.tokens.get(1).getType() != BlockTypes.VALUE && - this.tokens.get(1).getType() != BlockTypes.VARIABLE && - this.tokens.get(1).getType() != BlockTypes.NAMED_ARG) { - LOGGER.error( - SemanticKernelResources.getString( - "the.first.arg.of.a.function.must.be.a.quoted.string.variable.or.named.argument")); - return false; - } - - for (int i = 2; i < this.tokens.size(); i++) { - if (this.tokens.get(i).getType() != BlockTypes.NAMED_ARG) { - LOGGER.error( - SemanticKernelResources.getString( - "functions.only.support.named.arguments.after.the.first.argument"), - i); - return false; - } - } - - return true; - } - - @Override - public Mono renderCodeAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable InvocationContext context) { - if (!this.isValid()) { - throw new TemplateException(ErrorCodes.SYNTAX_ERROR); - } - - if (context == null) { - context = InvocationContext.builder().build(); - } - - switch (this.tokens.get(0).getType()) { - case VALUE: - case VARIABLE: - return Mono.just( - ((TextRendering) this.tokens.get(0)).render(context.getContextVariableTypes(), - arguments)); - - case FUNCTION_ID: - return this - .renderFunctionCallAsync( - (FunctionIdBlock) this.tokens.get(0), - kernel, - arguments, - context, - context.getContextVariableTypes().getVariableTypeForClass(String.class)) - .map(ContextVariable::getValue) - .map(StringEscapeUtils::escapeXml11); - - case UNDEFINED: - case TEXT: - case CODE: - default: - throw new RuntimeException("Unknown type"); - } - } - - private Mono> renderFunctionCallAsync( - FunctionIdBlock fBlock, - Kernel kernel, - @Nullable KernelArguments arguments, - InvocationContext context, - ContextVariableType resultType) { - - // If the code syntax is {{functionName $varName}} use $varName instead of $input - // If the code syntax is {{functionName 'value'}} use "value" instead of $input - if (this.tokens.size() > 1) { - //Cloning the original arguments to avoid side effects - arguments added to the original arguments collection as a result of rendering template variables. - arguments = this.enrichFunctionArguments(kernel, fBlock, - KernelArguments.builder().withVariables(arguments).build(), - context); - } - - return kernel - .invokeAsync( - fBlock.getPluginName(), - fBlock.getFunctionName()) - .withArguments(arguments) - .withResultType(resultType) - .map(FunctionResult::getResultVariable); - } - - ///

- /// Adds function arguments. If the first argument is not a named argument, it is added to the arguments collection as the 'input' argument. - /// Additionally, for the prompt expression - {{MyPlugin.MyFunction p1=$v1}}, the value of the v1 variable will be resolved from the original arguments collection. - /// Then, the new argument, p1, will be added to the arguments. - /// - /// Kernel instance. - /// Function block. - /// The prompt rendering arguments. - /// The function arguments. - /// Occurs when any argument other than the first is not a named argument. - private KernelArguments enrichFunctionArguments( - Kernel kernel, - FunctionIdBlock fBlock, - KernelArguments arguments, - @Nullable InvocationContext context) { - Block firstArg = this.tokens.get(1); - - ContextVariableTypes types = context == null ? new ContextVariableTypes() - : context.getContextVariableTypes(); - - // Get the function metadata - KernelFunctionMetadata functionMetadata = kernel - .getFunction(fBlock.getPluginName(), fBlock.getFunctionName()).getMetadata(); - - // Check if the function has parameters to be set - if (functionMetadata.getParameters().isEmpty()) { - throw new SKException( - "Function " + fBlock.getPluginName() + "." + fBlock.getFunctionName() - + " does not take any arguments but it is being called in the template with {this._tokens.Count - 1} arguments."); - } - - String firstPositionalParameterName = null; - Object firstPositionalInputValue = null; - int namedArgsStartIndex = 1; - - if (firstArg.getType() != BlockTypes.NAMED_ARG) { - // Gets the function first parameter name - firstPositionalParameterName = functionMetadata.getParameters().get(0).getName(); - - String contextVariableName = firstPositionalParameterName; - if (firstArg instanceof VarBlock) { - contextVariableName = ((VarBlock) firstArg).getName(); - } - - ContextVariable arg = arguments.get(contextVariableName); - Class desiredType = functionMetadata.getParameters().get(0).getTypeClass(); - - if (arg != null) { - try { - firstPositionalInputValue = ContextVariable.convert(arg, desiredType, types); - } catch (Exception e) { - // ignore - } - } - - if (firstPositionalInputValue == null) { - firstPositionalInputValue = ((TextRendering) tokens.get(1)).render(types, - arguments); - firstPositionalInputValue = ContextVariable - .convert( - firstPositionalInputValue, - functionMetadata.getParameters().get(0).getTypeClass(), - types); - } - - // Type check is avoided and marshalling is done by the function itself - if (firstPositionalInputValue == null) { - throw new SKException( - "Unexpected null value for first positional argument: " + tokens.get(1) - .getContent()); - } - - // Keep previous trust information when updating the input - arguments.put( - firstPositionalParameterName, - types.contextVariableOf(firstPositionalInputValue)); - namedArgsStartIndex++; - } - - for (int i = namedArgsStartIndex; i < this.tokens.size(); i++) { - // When casting fails because the block isn't a NamedArg, arg is null - if (!(this.tokens.get(i) instanceof NamedArgBlock)) { - throw new SKException("Unexpected first token type: {this._tokens[i].Type:G}"); - } - - NamedArgBlock arg = (NamedArgBlock) this.tokens.get(i); - - // Check if the positional parameter clashes with a named parameter - if (firstPositionalParameterName != null && - firstPositionalParameterName.equalsIgnoreCase(arg.getName())) { - throw new SKException( - "Ambiguity found as a named parameter '{arg.Name}' cannot be set for the first parameter when there is also a positional value: '{firstPositionalInputValue}' provided. Function: {fBlock.PluginName}.{fBlock.FunctionName}"); - } - - arguments.put(arg.getName(), types.contextVariableOf(arg.getValue(types, arguments))); - } - - return arguments; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java deleted file mode 100644 index 673bcf68a..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -/** - * Interface of dynamic blocks that need async IO to be rendered. - */ -public interface CodeRendering { - - /** - * Render the block using the given context, potentially using external I/O. - * - * @param kernel Kernel to use for rendering - * @param arguments Optional arguments used to render the block - * @param context Optional context used to render the block, typically used to pass {code - * KernelHooks} to the render method. - * @return Rendered content - * @see com.microsoft.semantickernel.hooks.KernelHooks - */ - Mono renderCodeAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable InvocationContext context); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java deleted file mode 100644 index 69e5a63be..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; - -/** - * Represents a function identifier block. - */ -public final class FunctionIdBlock extends Block implements TextRendering { - - private final String skillName; - - private final String functionName; - - /** - * Initializes a new instance of the {@link FunctionIdBlock} class. - * - * @param content The content. - */ - public FunctionIdBlock(String content) { - super(content, BlockTypes.FUNCTION_ID); - - String[] functionNameParts = this.getContent().split("\\.", -1); - if (functionNameParts.length > 2) { - throw new RuntimeException( - "A function name can contain at most one dot separating the plugin name from the" - + " function name"); - } - - if (functionNameParts.length == 2) { - this.skillName = functionNameParts[0]; - this.functionName = functionNameParts[1]; - return; - } - - this.functionName = this.getContent(); - this.skillName = ""; - } - - private static boolean hasMoreThanOneDot(String value) { - if (value == null || value.length() < 2) { - return false; - } - - return value.matches("^.*\\..*\\..*$"); - } - - @Override - @Nullable - public String render(ContextVariableTypes types, @Nullable KernelArguments variables) { - return this.getContent(); - } - - @Override - public boolean isValid() { - if (!this.getContent().matches("^[a-zA-Z0-9_.]*$")) { - // errorMsg = "The function identifier is empty"; - return false; - } - - if (hasMoreThanOneDot(this.getContent())) { - // errorMsg = "The function identifier can contain max one '.' char separating skill - // name from function name"; - return false; - } - - // errorMsg = ""; - return true; - } - - /** - * Get the plugin name. - * - * @return The plugin name. - */ - public String getPluginName() { - return skillName; - } - - /** - * Get the function name. - * - * @return The function name. - */ - public String getFunctionName() { - return functionName; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java deleted file mode 100644 index bed795020..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import static com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.BlockTypes.NAMED_ARG; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.Verify; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NamedArgBlock extends Block implements TextRendering { - - private static final Logger LOGGER = LoggerFactory.getLogger(NamedArgBlock.class); - - private final String name; - @Nullable - private final String value; - private final VarBlock argNameAsVarBlock; - @Nullable - private final VarBlock varBlock; - @Nullable - private final ValBlock valBlock; - - public NamedArgBlock(String content, String name, String value) { - super(content.trim(), NAMED_ARG); - this.name = name.trim(); - this.value = value.trim(); - - this.argNameAsVarBlock = new VarBlock(Symbols.VarPrefix + name); - - if (value.startsWith(String.valueOf(Symbols.VarPrefix))) { - this.varBlock = new VarBlock(value); - valBlock = null; - } else { - this.valBlock = new ValBlock(value); - varBlock = null; - } - } - - protected NamedArgBlock( - String content, - String name, - @Nullable String value, - VarBlock argNameAsVarBlock, - @Nullable VarBlock varBlock, - @Nullable ValBlock valBlock) { - super(content, NAMED_ARG); - this.name = name; - this.value = value; - this.argNameAsVarBlock = argNameAsVarBlock; - this.varBlock = varBlock; - this.valBlock = valBlock; - } - - public static NamedArgBlock from(String content) { - String name = tryGetName(content); - if (name == null) { - throw new SKException("Unable to extract name from: " + content); - } - String value = tryGetValue(content); - VarBlock argNameAsVarBlock = new VarBlock(Symbols.VarPrefix + name); - - if (value == null) { - throw new SKException("Unable to extract value from: " + content); - } - - VarBlock varBlock; - ValBlock valBlock; - - if (value.startsWith(String.valueOf(Symbols.VarPrefix))) { - varBlock = new VarBlock(value); - valBlock = null; - } else { - valBlock = new ValBlock(value); - varBlock = null; - } - - return new NamedArgBlock(content, name, value, argNameAsVarBlock, varBlock, valBlock); - } - - @Nullable - public static String tryGetName(String text) { - return splitAndGetPart(text, 0); - } - - @Nullable - public static String tryGetValue(String text) { - return splitAndGetPart(text, 1); - } - - @SuppressWarnings("StringSplitter") - @Nullable - private static String splitAndGetPart(String text, int x) { - if (Verify.isNullOrEmpty(text)) { - return null; - } - - String[] argBlockParts = text.split(String.valueOf(Symbols.NamedArgBlockSeparator)); - - if (argBlockParts.length == 2) { - return argBlockParts[x].trim(); - } - return null; - } - - @Override - public boolean isValid() { - if (Verify.isNullOrEmpty(this.name)) { - LOGGER.error(SemanticKernelResources.getString("a.named.argument.must.have.a.name")); - return false; - } - - if (this.valBlock != null && !this.valBlock.isValid()) { - LOGGER.error(SemanticKernelResources.getString( - "there.was.an.issue.with.the.named.argument.value.for"), name); - return false; - } else if (this.varBlock != null && !this.varBlock.isValid()) { - LOGGER.error(SemanticKernelResources.getString( - "there.was.an.issue.with.the.named.argument.value.for"), name); - return false; - } else if (this.valBlock == null && this.varBlock == null) { - LOGGER.error(SemanticKernelResources.getString("a.named.argument.must.have.a.value")); - return false; - } - - // Argument names share the same validation as variables - return this.argNameAsVarBlock.isValid(); - } - - @Override - public String render(ContextVariableTypes types, @Nullable KernelArguments variables) { - return getContent(); - } - - /// - /// Attempts to extract the name and value of a named argument block from a string - /// - /// String from which to extract a name and value - /// Name extracted from argument block, when successful. Empty string otherwise. - /// Value extracted from argument block, when successful. Empty string otherwise. - /// true when a name and value are successfully extracted from the given text, false otherwise - - @Nullable - public VarBlock getVarBlock() { - return varBlock; - - } - - public String getName() { - return name; - } - - @SuppressWarnings("NullAway") - public String getValue(ContextVariableTypes types, KernelArguments arguments) { - boolean valueIsValidValBlock = this.valBlock != null && this.valBlock.isValid(); - if (valueIsValidValBlock) { - return this.valBlock.render(types, arguments); - } - - boolean valueIsValidVarBlock = this.varBlock != null && this.varBlock.isValid(); - if (valueIsValidVarBlock) { - return this.varBlock.render(types, arguments); - } - - return ""; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Symbols.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Symbols.java deleted file mode 100644 index cfc579c9b..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/Symbols.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -public class Symbols { - - public static final char BlockStarter = '{'; - public static final char BlockEnder = '}'; - - public static final char VarPrefix = '$'; - public static final char NamedArgBlockSeparator = '='; - - public static final char DblQuote = '"'; - public static final char SglQuote = '\''; - public static final char EscapeChar = '\\'; - - public static final char Space = ' '; - public static final char Tab = '\t'; - public static final char NewLine = '\n'; - public static final char CarriageReturn = '\r'; -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java deleted file mode 100644 index 38128538e..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; - -public final class TextBlock extends Block implements TextRendering { - - public TextBlock(String text) { - super(text, BlockTypes.TEXT); - } - - public TextBlock(String text, int startIndex, int stopIndex) { - super(text.substring(startIndex, stopIndex), BlockTypes.TEXT); - } - - @Override - public boolean isValid() { - return true; - } - - @Override - public String render(ContextVariableTypes types, @Nullable KernelArguments variables) { - return super.getContent(); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java deleted file mode 100644 index 184b4ca45..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; - -/** - * Interface of static blocks that don't need async IO to be rendered. - */ -public interface TextRendering { - - /** - * Render the block using only the given variables. - * - * @param variables Optional variables used to render the block - * @return Rendered content - */ - @Nullable - String render(ContextVariableTypes types, @Nullable KernelArguments variables); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java deleted file mode 100644 index d81c84b9a..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.util.annotation.Nullable; - -public final class ValBlock extends Block implements TextRendering { - - private static final Logger LOGGER = LoggerFactory.getLogger(ValBlock.class); - - // Cache the first and last char - private char first = '\0'; - private char last = '\0'; - - // Content, excluding start/end quote chars - private String value = ""; - - public ValBlock(String quotedValue) { - super(quotedValue.trim(), BlockTypes.VALUE); - - if (this.getContent().length() < 2) { - LOGGER.error(SemanticKernelResources.getString( - "a.value.must.have.single.quotes.or.double.quotes.on.both.sides")); - return; - } - - this.first = this.getContent().charAt(0); - this.last = this.getContent().charAt(getContent().length() - 1); - this.value = this.getContent().substring(1, this.getContent().length() - 1); - } - - public static boolean hasValPrefix(@Nullable String text) { - return text != null - && !text.isEmpty() - && (text.charAt(0) == Symbols.DblQuote || text.charAt(0) == Symbols.SglQuote); - } - - @Override - @Nullable - public String render(ContextVariableTypes types, @Nullable KernelArguments variables) { - return value; - } - - @Override - public boolean isValid() { - // Content includes the quotes, so it must be at least 2 chars long - if (this.getContent().length() < 2) { - LOGGER.error(SemanticKernelResources.getString( - "a.value.must.have.single.quotes.or.double.quotes.on.both.sides")); - return false; - } - - // Check if delimiting chars are consistent - if (first != last) { - LOGGER.error( - SemanticKernelResources.getString( - "a.value.must.be.defined.using.either.single.quotes.or.double.quotes.not.both")); - return false; - } - - return true; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java deleted file mode 100644 index 5ae70bb32..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class VarBlock extends Block implements TextRendering { - - private static final Logger LOGGER = LoggerFactory.getLogger(VarBlock.class); - private final String name; - - public VarBlock(String content) { - super(content, BlockTypes.VARIABLE); - - if (content.length() < 2) { - LOGGER.error(SemanticKernelResources.getString("the.variable.name.is.empty")); - } - - this.name = content.substring(1); - } - - @Override - public String render(ContextVariableTypes types, @Nullable KernelArguments variables) { - if (variables == null) { - return ""; - } - - if (name == null || name.isEmpty()) { - throw new TemplateException( - TemplateException.ErrorCodes.SYNTAX_ERROR, - "Variable rendering failed, the variable name is empty"); - } - - ContextVariable value = variables.get( - name); - - if (value == null) { - LOGGER.warn(SemanticKernelResources.getString("variable.not.found"), Symbols.VarPrefix, - name); - } - - return value != null ? value.toPromptString(types) : ""; - } - - @Override - public boolean isValid() { - if (getContent() == null || getContent().isEmpty()) { - LOGGER.error( - SemanticKernelResources.getString( - "a.variable.must.start.with.the.symbol.and.have.a.name"), - Symbols.VarPrefix); - return false; - } - - if (getContent().charAt(0) != Symbols.VarPrefix) { - LOGGER.error(SemanticKernelResources.getString("a.variable.must.start.with.the.symbol"), - Symbols.VarPrefix); - return false; - } - - if (getContent().length() < 2) { - LOGGER.error(SemanticKernelResources.getString("the.variable.name.is.empty")); - return false; - } - - if (!name.matches("^[a-zA-Z0-9_]*$")) { - LOGGER.error( - SemanticKernelResources.getString( - "the.variable.name.contains.invalid.characters.only.alphanumeric.chars.and.underscore.are.allowed"), - name); - return false; - } - - return true; - } - - public String getName() { - return name; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java deleted file mode 100644 index 9b8a518c3..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.contextvariables.converters.ContextVariableJacksonConverter; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior; -import com.microsoft.semantickernel.hooks.KernelHook; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.NoSuchElementException; -import java.util.function.BiConsumer; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.CoreSubscriber; -import reactor.core.publisher.Mono; -import reactor.core.publisher.SynchronousSink; - -/** - * {@code FunctionInvocation} supports fluent invocation of a function in the kernel. - * - * @param The type of the result of the function invocation. - */ -public class FunctionInvocation extends Mono> { - - private static final Logger LOGGER = LoggerFactory.getLogger(FunctionInvocation.class); - - protected final KernelFunction function; - - protected final Kernel kernel; - @Nullable - protected final ContextVariableType resultType; - protected final ContextVariableTypes contextVariableTypes = new ContextVariableTypes(); - @Nullable - protected KernelArguments arguments; - @Nullable - protected UnmodifiableKernelHooks hooks; - @Nullable - protected PromptExecutionSettings promptExecutionSettings; - @Nullable - protected ToolCallBehavior toolCallBehavior; - @Nullable - protected FunctionChoiceBehavior functionChoiceBehavior; - - @Nullable - protected SemanticKernelTelemetry telemetry; - - private boolean isSubscribed = false; - - /** - * Create a new function invocation. - * - * @param kernel The kernel to invoke the function on. - * @param function The function to invoke. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public FunctionInvocation( - Kernel kernel, - KernelFunction function) { - this.function = function; - this.kernel = kernel; - this.resultType = null; - this.addKernelHooks(kernel.getGlobalKernelHooks()); - } - - /** - * Create a new function invocation. - * - * @param kernel The kernel to invoke the function on. - * @param function The function to invoke. - * @param resultType The type of the result of the function invocation. - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public FunctionInvocation( - Kernel kernel, - KernelFunction function, - @Nullable ContextVariableType resultType) { - this.function = function; - this.kernel = kernel; - this.resultType = resultType; - if (resultType != null) { - contextVariableTypes.putConverter(resultType.getConverter()); - } - this.addKernelHooks(kernel.getGlobalKernelHooks()); - } - - // Extracted to static to ensure mutable state is not used - private static void performSubscribe( - CoreSubscriber> coreSubscriber, - Kernel kernel, - KernelFunction function, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext context) { - if (variableType == null) { - LOGGER.debug( - SemanticKernelResources.getString( - "no.variable.type.explicitly.specified.by.calling.withresulttype.for.function"), - function.getPluginName(), - function.getName()); - } - - InvocationContext contextClone = new InvocationContext(context); - - function - .invokeAsync( - kernel, - KernelArguments - .builder() - .withVariables(arguments) - .build(), - null, - contextClone) - .handle(convertToType(variableType, contextClone.getContextVariableTypes())) - .onErrorResume(e -> { - if (e instanceof NoSuchElementException) { - return Mono.empty(); - } else { - return Mono.error(e); - } - }) - .subscribe(coreSubscriber); - } - - private static BiConsumer, SynchronousSink>> convertToType( - @Nullable ContextVariableType variableType, - @Nullable ContextVariableTypes contextVariableTypes) { - return (result, sink) -> { - // If a specific result type was requested, convert the result to that type. - if (variableType != null) { - try { - ContextVariableTypes types = new ContextVariableTypes(contextVariableTypes); - types.putConverter(variableType.getConverter()); - - sink.next(new FunctionResult<>( - ContextVariable.convert(result.getResult(), variableType.getClazz(), types), - result.getMetadata(), - result.getUnconvertedResult())); - } catch (Exception e) { - sink.error(new SKException( - "Failed to convert result to requested type: " - + variableType.getClazz().getName() + " " + result.getResult(), - e)); - } - } else { - // Otherwise, just pass the result through and trust that the user requested the correct type. - sink.next((FunctionResult) result); - } - }; - } - - @Nullable - private static UnmodifiableKernelHooks unmodifiableClone( - @Nullable KernelHooks kernelHooks) { - if (kernelHooks instanceof UnmodifiableKernelHooks) { - return (UnmodifiableKernelHooks) kernelHooks; - } else if (kernelHooks != null) { - return kernelHooks.unmodifiableClone(); - } else { - return null; - } - } - - /** - * Supply arguments to the function invocation. - * - * @param arguments The arguments to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withArguments( - @Nullable KernelArguments arguments) { - logSubscribeWarning(); - this.arguments = KernelArguments.builder().withVariables(arguments).build(); - return this; - } - - /** - * Supply the result type of function invocation. - * - * @param resultType The arguments to supply to the function invocation. - * @param The type of the result of the function invocation. - * @return A new {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withResultType(ContextVariableType resultType) { - logSubscribeWarning(); - return new FunctionInvocation<>( - kernel, - function, - resultType) - .withArguments(arguments) - .addKernelHooks(hooks) - .withPromptExecutionSettings(promptExecutionSettings) - .withFunctionChoiceBehavior(functionChoiceBehavior) - .withToolCallBehavior(toolCallBehavior) - .withTypes(contextVariableTypes); - } - - /** - * Supply the result type of function invocation. Also registers a type converter for the given - * type using {@code} ContextVariableJacksonConverter.create}. - * - * @param resultType The arguments to supply to the function invocation. - * @param The type of the result of the function invocation. - * @return A new {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withResultTypeAutoConversion(Class resultType) { - try { - return withTypeConverter(ContextVariableJacksonConverter.create(resultType)) - .withResultType(contextVariableTypes.getVariableTypeForSuperClass(resultType)); - } catch (SKException e) { - return withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(resultType)); - } - } - - /** - * Supply the result type of function invocation. Uses the global context variable types. - * - * @param resultType The arguments to supply to the function invocation. - * @param The type of the result of the function invocation. - * @return A new {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withResultType(Class resultType) { - try { - return withResultType(contextVariableTypes.getVariableTypeForSuperClass(resultType)); - } catch (SKException e) { - return withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(resultType)); - } - } - - /** - * Add a kernel hook to the function invocation. - * - * @param hook The kernel hook to add. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation addKernelHook(@Nullable KernelHook hook) { - if (hook == null) { - return this; - } - logSubscribeWarning(); - KernelHooks clone = new KernelHooks(this.hooks); - clone.addHook(hook); - this.hooks = unmodifiableClone(clone); - return this; - } - - /** - * Add kernel hooks to the function invocation. - * - * @param hooks The kernel hooks to add. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation addKernelHooks( - @Nullable KernelHooks hooks) { - if (hooks == null) { - return this; - } - logSubscribeWarning(); - this.hooks = unmodifiableClone(new KernelHooks(this.hooks).addHooks(hooks)); - return this; - } - - /** - * Supply prompt execution settings to the function invocation. - * - * @param promptExecutionSettings The prompt execution settings to supply to the function - * invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withPromptExecutionSettings( - @Nullable PromptExecutionSettings promptExecutionSettings) { - logSubscribeWarning(); - this.promptExecutionSettings = promptExecutionSettings; - return this; - } - - /** - * Supply tool call behavior to the function invocation. - * - * @param toolCallBehavior The tool call behavior to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withToolCallBehavior(@Nullable ToolCallBehavior toolCallBehavior) { - logSubscribeWarning(); - if (toolCallBehavior != null && functionChoiceBehavior != null) { - throw new SKException( - "ToolCallBehavior cannot be set when FunctionChoiceBehavior is set."); - } - this.toolCallBehavior = toolCallBehavior; - return this; - } - - /** - * Supply function choice behavior to the function invocation. - * - * @param functionChoiceBehavior The function choice behavior to supply to the function - * invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withFunctionChoiceBehavior( - @Nullable FunctionChoiceBehavior functionChoiceBehavior) { - if (functionChoiceBehavior != null && toolCallBehavior != null) { - throw new SKException( - "FunctionChoiceBehavior cannot be set when ToolCallBehavior is set."); - } - logSubscribeWarning(); - this.functionChoiceBehavior = functionChoiceBehavior; - return this; - } - - /** - * Supply a type converter to the function invocation. - * - * @param typeConverter The type converter to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withTypeConverter(ContextVariableTypeConverter typeConverter) { - logSubscribeWarning(); - contextVariableTypes.putConverter(typeConverter); - return this; - } - - /** - * Supply a context variable type to the function invocation. - * - * @param contextVariableTypes The context variable types to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withTypes(ContextVariableTypes contextVariableTypes) { - logSubscribeWarning(); - this.contextVariableTypes.putConverters(contextVariableTypes); - return this; - } - - /** - * Supply a tracer to the function invocation. - * - * @param tracer The tracer to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withTelemetry(SemanticKernelTelemetry telemetry) { - this.telemetry = telemetry; - return this; - } - - /** - * Use an invocation context variable to supply the types, tool call behavior, prompt execution - * settings, and kernel hooks to the function invocation. - * - * @param invocationContext The invocation context to supply to the function invocation. - * @return this {@code FunctionInvocation} for fluent chaining. - */ - public FunctionInvocation withInvocationContext( - @Nullable InvocationContext invocationContext) { - if (invocationContext == null) { - return this; - } - logSubscribeWarning(); - withTypes(invocationContext.getContextVariableTypes()); - withFunctionChoiceBehavior(invocationContext.getFunctionChoiceBehavior()); - withToolCallBehavior(invocationContext.getToolCallBehavior()); - withPromptExecutionSettings(invocationContext.getPromptExecutionSettings()); - addKernelHooks(invocationContext.getKernelHooks()); - withTelemetry(invocationContext.getTelemetry()); - return this; - } - - private void logSubscribeWarning() { - if (isSubscribed) { - LOGGER.warn( - SemanticKernelResources.getString( - "attempting.to.modify.function.after.it.has.already.been.subscribed"), - function.getPluginName(), function.getName()); - } - } - - /** - * This method handles the reactive stream when the KernelFunction is invoked. - * - * @param coreSubscriber The subscriber to subscribe to the function invocation. - */ - @Override - public void subscribe(CoreSubscriber> coreSubscriber) { - - if (isSubscribed) { - LOGGER.warn( - SemanticKernelResources.getString( - "function.has.already.been.subscribed.to.this.is.not.necessarily.an.error.but.may.be.an.unusual.pattern"), - function.getPluginName(), function.getName()); - } - - if (telemetry == null) { - telemetry = new SemanticKernelTelemetry(); - } - - isSubscribed = true; - - performSubscribe( - coreSubscriber, - kernel, - function, - arguments, - resultType, - new InvocationContext( - hooks, - promptExecutionSettings, - toolCallBehavior, - functionChoiceBehavior, - contextVariableTypes, - InvocationReturnMode.NEW_MESSAGES_ONLY, - telemetry)); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java deleted file mode 100644 index 510bb65fa..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import javax.annotation.Nullable; - -/** - * The result of a function invocation. - *

- * This class is used to return the result of a function invocation. It contains the result of the - * function invocation and metadata about the result. - * - * @param The type of the result of the function invocation. - */ -public class FunctionResult { - - private final ContextVariable result; - private final FunctionResultMetadata metadata; - @Nullable - private final Object unconvertedResult; - - /** - * Create a new instance of FunctionResult. - * - * @param result The result of the function invocation. - * @param metadata Metadata about the result of the function invocation. - * @param unconvertedResult The result of the function invocation before it was converted to the - * expected type. - */ - public FunctionResult( - ContextVariable result, - @Nullable FunctionResultMetadata metadata, - @Nullable Object unconvertedResult) { - this.result = result; - this.metadata = metadata == null ? FunctionResultMetadata.empty() : metadata; - this.unconvertedResult = unconvertedResult; - } - - /** - * Create a new instance of FunctionResult with no metadata. - * - * @param of The result of the function invocation. - * @param unconvertedResult The result of the function invocation before it was converted to the - * expected type. - */ - public FunctionResult(ContextVariable of, - @Nullable Object unconvertedResult) { - this(of, FunctionResultMetadata.empty(), unconvertedResult); - } - - /** - * Get the result of the function invocation. - * NOTE: If you get a ClassCastException from this method, - * try adding a result type with {@link FunctionInvocation#withResultType(ContextVariableType)} - * )} - * - * @return The result of the function invocation. - * @throws ClassCastException If the result is not of the expected type. - */ - @Nullable - public T getResult() { - return result.getValue(); - } - - /** - * Get the result of the function invocation. - * - * @return The result of the function invocation. - */ - public ContextVariable getResultVariable() { - return result; - } - - /** - * Get the metadata about the result of the function invocation. - * - * @return The metadata about the result of the function invocation. - */ - public FunctionResultMetadata getMetadata() { - return metadata; - } - - /** - * Get the result of the function invocation before it was converted to the expected type. - * - * @return The result of the function invocation before it was converted to the expected type. - */ - @Nullable - public Object getUnconvertedResult() { - return unconvertedResult; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResultMetadata.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResultMetadata.java deleted file mode 100644 index 9bb55d11d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResultMetadata.java +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; - -import java.time.OffsetDateTime; -import javax.annotation.Nullable; - -/** - * Metadata about the result of a function invocation. - *

- * This class is used to return metadata about the result of a function invocation. - * @param The result type of the function invocation. - */ -public class FunctionResultMetadata { - - /** - * The key for id metadata. - */ - public static final String ID = "id"; - - /** - * The key for usage metadata. - */ - public static final String USAGE = "usage"; - - /** - * The key for createdAt metadata. - */ - public static final String CREATED_AT = "createdAt"; - - private final CaseInsensitiveMap> metadata; - - /** - * Create a new instance of FunctionResultMetadata. - */ - public FunctionResultMetadata() { - this.metadata = new CaseInsensitiveMap<>(); - } - - /** - * Create a new instance of FunctionResultMetadata. - * - * @param metadata Metadata about the result of the function invocation. - */ - public FunctionResultMetadata(CaseInsensitiveMap> metadata) { - this.metadata = new CaseInsensitiveMap<>(metadata); - } - - /** - * Create a new instance of FunctionResultMetadata. - * @param id The id of the result of the function invocation. - * @return A new instance of FunctionResultMetadata. - */ - public static FunctionResultMetadata build(String id) { - return build(id, null, null); - } - - /** - * Create a new instance of FunctionResultMetadata. - * - * @param id The id of the result of the function invocation. - * @param usage The usage of the result of the function invocation. - * @param createdAt The time the result was created. - * @param The result type of the function invocation. - * @return A new instance of FunctionResultMetadata. - */ - public static FunctionResultMetadata build( - String id, - @Nullable UsageType usage, - @Nullable OffsetDateTime createdAt) { - - CaseInsensitiveMap> metadata = new CaseInsensitiveMap<>(); - - metadata.put(ID, ContextVariable.of(id)); - - if (usage != null) { - metadata.put(USAGE, ContextVariable.of(usage, - new ContextVariableTypeConverter.NoopConverter<>(Object.class))); - } - if (createdAt != null) { - metadata.put(CREATED_AT, ContextVariable.of(createdAt)); - } - - return new FunctionResultMetadata<>(metadata); - } - - /** - * Create a new instance of FunctionResultMetadata with no metadata. - * - * @return A new instance of FunctionResultMetadata. - */ - public static FunctionResultMetadata empty() { - return new FunctionResultMetadata<>(new CaseInsensitiveMap<>()); - } - - /** - * Get the metadata about the result of the function invocation. - * - * @return The metadata about the result of the function invocation. - */ - public CaseInsensitiveMap> getMetadata() { - return new CaseInsensitiveMap<>(metadata); - } - - /** - * Get the id of the result of the function invocation. - * - * @return The id of the result of the function invocation. - */ - @Nullable - public String getId() { - ContextVariable id = metadata.get(ID); - if (id == null) { - return null; - } - return id.getValue(String.class); - } - - /** - * Get the usage of the result of the function invocation. - * - * @return The usage of the result of the function invocation. - */ - @Nullable - public UsageType getUsage() { - ContextVariable usage = metadata.get(USAGE); - if (usage == null) { - return null; - } - return (UsageType) usage.getValue(Object.class); - } - - /** - * Get the time the result was created. - * - * @return The time the result was created. - */ - @Nullable - public OffsetDateTime getCreatedAt() { - ContextVariable createdAt = metadata.get(CREATED_AT); - if (createdAt == null) { - return null; - } - return createdAt.getValue(OffsetDateTime.class); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java deleted file mode 100644 index 6a8547c43..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import javax.annotation.Nullable; - -/** - * Context passed to a Kernel or KernelFunction invoke. This class is primarily for internal use. - * The preferred way to supply a context is to use the discrete "with" methods in - * {@link FunctionInvocation}. - */ -public class InvocationContext { - - @Nullable - private final UnmodifiableKernelHooks hooks; - @Nullable - private final PromptExecutionSettings promptExecutionSettings; - @Nullable - private final ToolCallBehavior toolCallBehavior; - @Nullable - private final FunctionChoiceBehavior functionChoiceBehavior; - private final ContextVariableTypes contextVariableTypes; - private final InvocationReturnMode invocationReturnMode; - private final SemanticKernelTelemetry telemetry; - - /** - * Create a new instance of InvocationContext. - * - * @param hooks The hooks to use for the invocation. - * @param promptExecutionSettings The settings for prompt execution. - * @param toolCallBehavior The behavior for tool calls. - * @param contextVariableTypes The types of context variables. - */ - protected InvocationContext( - @Nullable KernelHooks hooks, - @Nullable PromptExecutionSettings promptExecutionSettings, - @Nullable ToolCallBehavior toolCallBehavior, - @Nullable FunctionChoiceBehavior functionChoiceBehavior, - @Nullable ContextVariableTypes contextVariableTypes, - InvocationReturnMode invocationReturnMode, - SemanticKernelTelemetry telemetry) { - this.hooks = unmodifiableClone(hooks); - this.promptExecutionSettings = promptExecutionSettings; - this.toolCallBehavior = toolCallBehavior; - this.functionChoiceBehavior = functionChoiceBehavior; - this.invocationReturnMode = invocationReturnMode; - if (contextVariableTypes == null) { - this.contextVariableTypes = new ContextVariableTypes(); - } else { - this.contextVariableTypes = new ContextVariableTypes(contextVariableTypes); - } - this.telemetry = telemetry; - } - - /** - * Create a new instance of InvocationContext. - */ - protected InvocationContext() { - this.hooks = null; - this.promptExecutionSettings = null; - this.toolCallBehavior = null; - this.functionChoiceBehavior = null; - this.contextVariableTypes = new ContextVariableTypes(); - this.invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY; - this.telemetry = null; - } - - /** - * Create a new instance of InvocationContext. - * - * @param context The context to copy. - */ - protected InvocationContext(@Nullable InvocationContext context) { - if (context == null) { - this.hooks = null; - this.promptExecutionSettings = null; - this.toolCallBehavior = null; - this.functionChoiceBehavior = null; - this.contextVariableTypes = new ContextVariableTypes(); - this.invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY; - this.telemetry = null; - } else { - this.hooks = context.hooks; - this.promptExecutionSettings = context.promptExecutionSettings; - this.toolCallBehavior = context.toolCallBehavior; - this.functionChoiceBehavior = context.functionChoiceBehavior; - this.contextVariableTypes = context.contextVariableTypes; - this.invocationReturnMode = context.invocationReturnMode; - this.telemetry = context.telemetry; - } - } - - /** - * Create a new {@link Builder} for building an instance of {@code InvocationContext}. - * - * @return the new Builder. - */ - public static Builder builder() { - return new Builder(); - } - - @Nullable - private static UnmodifiableKernelHooks unmodifiableClone( - @Nullable KernelHooks kernelHooks) { - if (kernelHooks instanceof UnmodifiableKernelHooks) { - return (UnmodifiableKernelHooks) kernelHooks; - } else if (kernelHooks != null) { - return kernelHooks.unmodifiableClone(); - } else { - return null; - } - } - - /** - * Create a new instance of InvocationContext by copying the values from another instance. - * - * @param context The context to copy. - * @return The new instance of InvocationContext. - */ - public static Builder copy(InvocationContext context) { - return new Builder() - .withKernelHooks(context.getKernelHooks()) - .withContextVariableConverter(context.contextVariableTypes) - .withPromptExecutionSettings(context.getPromptExecutionSettings()) - .withToolCallBehavior(context.getToolCallBehavior()) - .withTelemetry(context.getTelemetry()); - } - - /** - * Get the hooks to use for the invocation. - * - * @return The hooks to use for the invocation. - */ - @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "returns UnmodifiableKernelHooks") - @Nullable - public UnmodifiableKernelHooks getKernelHooks() { - return hooks; - } - - /** - * Get the settings for prompt execution. - * - * @return The settings for prompt execution. - */ - @Nullable - public PromptExecutionSettings getPromptExecutionSettings() { - return promptExecutionSettings; - } - - /** - * Get the behavior for tool calls. - * - * @return The behavior for tool calls. - */ - @Nullable - public ToolCallBehavior getToolCallBehavior() { - return toolCallBehavior; - } - - /** - * Get the behavior for function choice. - * - * @return The behavior for function choice. - */ - @Nullable - public FunctionChoiceBehavior getFunctionChoiceBehavior() { - return functionChoiceBehavior; - } - - /** - * Get the types of context variables. - * - * @return The types of context variables. - */ - public ContextVariableTypes getContextVariableTypes() { - return new ContextVariableTypes(contextVariableTypes); - } - - /** - * Get the return mode for the invocation. - * - * @return this {@link Builder} - */ - public InvocationReturnMode returnMode() { - return invocationReturnMode; - } - - public SemanticKernelTelemetry getTelemetry() { - return telemetry; - } - - /** - * Builder for {@link InvocationContext}. - */ - public static class Builder implements SemanticKernelBuilder { - - private final ContextVariableTypes contextVariableTypes = new ContextVariableTypes(); - @Nullable - private UnmodifiableKernelHooks hooks; - @Nullable - private PromptExecutionSettings promptExecutionSettings; - @Nullable - private ToolCallBehavior toolCallBehavior; - @Nullable - private FunctionChoiceBehavior functionChoiceBehavior; - private InvocationReturnMode invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY; - @Nullable - private SemanticKernelTelemetry telemetry; - - /** - * Add kernel hooks to the builder. - * - * @param hooks the hooks to add. - * @return this {@link Builder} - */ - public Builder withKernelHooks( - @Nullable KernelHooks hooks) { - this.hooks = unmodifiableClone(hooks); - return this; - } - - /** - * Add prompt execution settings to the builder. - * - * @param promptExecutionSettings the settings to add. - * @return this {@link Builder} - */ - public Builder withPromptExecutionSettings( - @Nullable PromptExecutionSettings promptExecutionSettings) { - this.promptExecutionSettings = promptExecutionSettings; - return this; - } - - /** - * Add tool call behavior to the builder. - * - * @param toolCallBehavior the behavior to add. - * @return this {@link Builder} - */ - public Builder withToolCallBehavior( - @Nullable ToolCallBehavior toolCallBehavior) { - if (toolCallBehavior != null && functionChoiceBehavior != null) { - throw new SKException( - "ToolCallBehavior cannot be set when FunctionChoiceBehavior is set."); - } - this.toolCallBehavior = toolCallBehavior; - return this; - } - - /** - * Add function choice behavior to the builder. - * - * @param functionChoiceBehavior the behavior to add. - * @return this {@link Builder} - */ - public Builder withFunctionChoiceBehavior( - @Nullable FunctionChoiceBehavior functionChoiceBehavior) { - if (functionChoiceBehavior != null && toolCallBehavior != null) { - throw new SKException( - "FunctionChoiceBehavior cannot be set when ToolCallBehavior is set."); - } - this.functionChoiceBehavior = functionChoiceBehavior; - return this; - } - - /** - * Add a context variable type converter to the builder. - * - * @param converter the converter to add. - * @return this {@link Builder} - */ - public Builder withContextVariableConverter(ContextVariableTypeConverter converter) { - this.contextVariableTypes.putConverter( - converter); - return this; - } - - /** - * Add a context variable type converter to the builder. - * - * @param contextVariableTypes the context variable types to add. - * @return this {@link Builder} - */ - public Builder withContextVariableConverter(ContextVariableTypes contextVariableTypes) { - this.contextVariableTypes.putConverters(contextVariableTypes); - return this; - } - - /** - * Set the return mode for the invocation. - *

- * Defaults to {@link InvocationReturnMode#NEW_MESSAGES_ONLY}. - * - * @param invocationReturnMode the return mode for the invocation. - * @return this {@link Builder} - */ - public Builder withReturnMode(InvocationReturnMode invocationReturnMode) { - this.invocationReturnMode = invocationReturnMode; - return this; - } - - /** - * Add a tracer to the builder. - * - * @param telemetry the tracer to add. - * @return this {@link Builder} - */ - public Builder withTelemetry(@Nullable SemanticKernelTelemetry telemetry) { - this.telemetry = telemetry; - return this; - } - - @Override - public InvocationContext build() { - if (telemetry == null) { - telemetry = new SemanticKernelTelemetry(); - } - return new InvocationContext(hooks, promptExecutionSettings, toolCallBehavior, - functionChoiceBehavior, - contextVariableTypes, invocationReturnMode, telemetry); - } - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationReturnMode.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationReturnMode.java deleted file mode 100644 index 48c279f20..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationReturnMode.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -/** - * Represents the mode in which a function invocation should return its results. - */ -public enum InvocationReturnMode { - /** - * Function invocations that build upon a history of previous invocations, such as Chat - * Completions, will return the full history of messages. - */ - FULL_HISTORY, - /** - * Function invocations that build upon a history of previous invocations, such as Chat - * Completions, will return only new messages generated by the given invocation. - *

- * This is the expected default behavior for most use cases. - */ - NEW_MESSAGES_ONLY, - /** - * Function invocations that build upon a history of previous invocations, such as Chat - * Completions, will return only the last message generated by the given invocation. - */ - LAST_MESSAGE_ONLY -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java deleted file mode 100644 index 19dfbd0dd..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java +++ /dev/null @@ -1,626 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.responseformat.JsonObjectResponseFormat; -import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.orchestration.responseformat.ResponseFormat; -import com.microsoft.semantickernel.orchestration.responseformat.TextResponseFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * Configuration settings for prompt execution. - */ -public class PromptExecutionSettings { - - /** - * The default for {@link #getServiceId()} if a {@link Builder#withServiceId(String) service id} - * is not provided. Defaults to {@code "default"} - */ - public static final String DEFAULT_SERVICE_ID = "default"; - - /** - * The default for {@link #getMaxTokens()} if {@link Builder#withMaxTokens(int) max_tokens} is - * not provided. Defaults to {@code 256} - */ - public static final int DEFAULT_MAX_TOKENS = 256; - - /** - * The default for {@link #getTemperature()} if - * {@link Builder#withTemperature(double) temperature} is not provided. Defaults to {@code 1.0} - */ - public static final double DEFAULT_TEMPERATURE = 1.0; - - /** - * The default for {@link #getTopP()} if {@link Builder#withTopP(double) top_p} is not provided. - * Defaults to {@code 1.0} - */ - public static final double DEFAULT_TOP_P = 1.0; - - /** - * The default for {@link #getPresencePenalty()} if - * {@link Builder#withPresencePenalty(double) presence_penalty} is not provided. Defaults to - * {@code 0.0} - */ - public static final double DEFAULT_PRESENCE_PENALTY = 0.0; - - /** - * The default for {@link #getFrequencyPenalty()} if - * {@link Builder#withFrequencyPenalty(double)} frequency_penalty} is not provided. Defaults to - * {@code 0.0} - */ - public static final double DEFAULT_FREQUENCY_PENALTY = 0.0; - - /** - * The default for {@link #getBestOf()} if {@link Builder#withBestOf(int) best_of} is not - * provided. Defaults to {@code 1} - */ - public static final int DEFAULT_BEST_OF = 1; - - /** - * The default for {@link #getResultsPerPrompt()} if - * {@link Builder#withResultsPerPrompt(int) results per prompt (n)} is not provided. Defaults to - * {@code 1} - */ - public static final int DEFAULT_RESULTS_PER_PROMPT = 1; - - // - // Keys used as both @JsonProperty names and keys to the Builder's value map. - // - private static final String SERVICE_ID = "service_id"; - private static final String MODEL_ID = "model_id"; - private static final String TEMPERATURE = "temperature"; - private static final String TOP_P = "top_p"; - private static final String PRESENCE_PENALTY = "presence_penalty"; - private static final String FREQUENCY_PENALTY = "frequency_penalty"; - private static final String MAX_TOKENS = "max_tokens"; - private static final String BEST_OF = "best_of"; - private static final String USER = "user"; - private static final String STOP_SEQUENCES = "stop_sequences"; - private static final String RESULTS_PER_PROMPT = "results_per_prompt"; - private static final String TOKEN_SELECTION_BIASES = "token_selection_biases"; - private static final String RESPONSE_FORMAT = "response_format"; - - private final String serviceId; - private final String modelId; - private final double temperature; - private final double topP; - private final double presencePenalty; - private final double frequencyPenalty; - private final int maxTokens; - private final int bestOf; - private final int resultsPerPrompt; - private final String user; - private final List stopSequences; - private final Map tokenSelectionBiases; - private final ResponseFormat responseFormat; - - /** - * Create a new instance of PromptExecutionSettings. - * - * @param serviceId The id of the AI service to use for prompt execution. - * @param modelId The id of the model to use for prompt execution. - * @param temperature The temperature setting for prompt execution. - * @param topP The topP setting for prompt execution. - * @param presencePenalty The presence penalty setting for prompt execution. - * @param frequencyPenalty The frequency penalty setting for prompt execution. - * @param maxTokens The maximum number of tokens to generate in the output. - * @param resultsPerPrompt The number of results to generate for each prompt. - * @param bestOf The best of setting for prompt execution. - * @param user The user to associate with the prompt execution. - * @param stopSequences The stop sequences to use for prompt execution. - * @param tokenSelectionBiases The token selection biases to use for prompt execution. - * @param responseFormat The response format to use for prompt execution - * {@link ResponseFormat}, Defaults to TextResponseFormat. - */ - @JsonCreator - public PromptExecutionSettings( - @JsonProperty(SERVICE_ID) String serviceId, - @JsonProperty(MODEL_ID) String modelId, - @JsonProperty(TEMPERATURE) Double temperature, - @JsonProperty(TOP_P) Double topP, - @JsonProperty(PRESENCE_PENALTY) Double presencePenalty, - @JsonProperty(FREQUENCY_PENALTY) Double frequencyPenalty, - @JsonProperty(MAX_TOKENS) Integer maxTokens, - @JsonProperty(RESULTS_PER_PROMPT) Integer resultsPerPrompt, - @JsonProperty(BEST_OF) Integer bestOf, - @JsonProperty(USER) String user, - @Nullable @JsonProperty(STOP_SEQUENCES) List stopSequences, - @Nullable @JsonProperty(TOKEN_SELECTION_BIASES) Map tokenSelectionBiases, - @Nullable @JsonProperty(RESPONSE_FORMAT) ResponseFormat responseFormat) { - this.serviceId = serviceId != null ? serviceId : DEFAULT_SERVICE_ID; - this.modelId = modelId != null ? modelId : ""; - this.temperature = clamp(temperature, 0d, 2d, DEFAULT_TEMPERATURE); - this.topP = clamp(topP, 0d, 1d, DEFAULT_TOP_P); - this.presencePenalty = clamp(presencePenalty, -2d, 2d, DEFAULT_PRESENCE_PENALTY); - this.frequencyPenalty = clamp(frequencyPenalty, -2d, 2d, DEFAULT_FREQUENCY_PENALTY); - this.maxTokens = clamp(maxTokens, 1, Integer.MAX_VALUE, DEFAULT_MAX_TOKENS); - this.resultsPerPrompt = clamp(resultsPerPrompt, 1, Integer.MAX_VALUE, - DEFAULT_RESULTS_PER_PROMPT); - this.bestOf = clamp(bestOf, 1, Integer.MAX_VALUE, DEFAULT_BEST_OF); - this.user = user != null ? user : ""; - this.stopSequences = stopSequences != null ? new ArrayList<>(stopSequences) - : Collections.emptyList(); - this.tokenSelectionBiases = tokenSelectionBiases != null - ? new HashMap<>(tokenSelectionBiases) - : Collections.emptyMap(); - this.tokenSelectionBiases.replaceAll((k, v) -> clamp(v, -100, 100, 0)); - - if (responseFormat == null) { - this.responseFormat = new TextResponseFormat(); - } else { - this.responseFormat = responseFormat; - } - } - - /** - * Create a new builder for PromptExecutionSettings. - * - * @return A new builder for PromptExecutionSettings. - */ - public static Builder builder() { - return new Builder(); - } - - private static T clamp(T value, T min, T max, T defaultValue) { - if (value == null) { - return defaultValue; - } - if (value.doubleValue() < min.doubleValue()) { - return min; - } - if (value.doubleValue() > max.doubleValue()) { - return max; - } - return value; - } - - /** - * Get the id of the AI service to use for prompt execution. - * - * @return The id of the AI service to use for prompt execution. - */ - @JsonProperty(SERVICE_ID) - public String getServiceId() { - return serviceId; - } - - /** - * Get the id of the model to use for prompt execution. - * - * @return The id of the model to use for prompt execution. - */ - @JsonProperty(MODEL_ID) - public String getModelId() { - return modelId; - } - - /** - * The temperature setting controls the randomness of the output. Lower values produce more - * deterministic outputs, while higher values produce more random outputs. - * - * @return The temperature setting. - */ - @JsonProperty(TEMPERATURE) - public double getTemperature() { - return Double.isNaN(temperature) ? DEFAULT_TEMPERATURE : temperature; - } - - /** - * The topP setting controls how many different words or phrases are considered to predict the - * next token. The value is a probability threshold, and the model considers the most likely - * tokens whose cumulative probability mass is greater than the threshold. For example, if the - * value is 0.1, the model considers only the tokens that make up the top 10% of the cumulative - * probability mass. - * - * @return The topP setting. - */ - @JsonProperty(TOP_P) - public double getTopP() { - return topP; - } - - /** - * Presence penalty encourages the model to use a more or less diverse range of tokens in the - * output. A higher value means that the model will try to use a greater variety of tokens in - * the output. - * - * @return The presence penalty setting. - */ - @JsonProperty(PRESENCE_PENALTY) - public double getPresencePenalty() { - return presencePenalty; - } - - /** - * Frequency penalty encourages the model to avoid repeating the same token in the output. A - * higher value means that the model will be less likely to repeat a token. - * - * @return The frequency penalty setting. - */ - @JsonProperty(FREQUENCY_PENALTY) - public double getFrequencyPenalty() { - return frequencyPenalty; - } - - /** - * The maximum number of tokens to generate in the output. - * - * @return The maximum number of tokens to generate in the output. - */ - @JsonProperty(MAX_TOKENS) - public int getMaxTokens() { - return maxTokens; - } - - /** - * The number of results to generate for each prompt. - * - * @return The number of results to generate for each prompt. - */ - @JsonProperty(RESULTS_PER_PROMPT) - public int getResultsPerPrompt() { - return resultsPerPrompt; - } - - /** - * The log probability threshold for a result to be considered. - * - * @return The log probability threshold for a result to be considered. - */ - @JsonProperty(BEST_OF) - public int getBestOf() { - // TODO: not present in com.azure:azure-ai-openai - return bestOf; - } - - /** - * The user to associate with the prompt execution. - * - * @return The user to associate with the prompt execution. - */ - @JsonProperty(USER) - public String getUser() { - return user; - } - - /** - * The stop sequences to use for prompt execution. - * - * @return The stop sequences to use for prompt execution. - */ - @JsonProperty(STOP_SEQUENCES) - public List getStopSequences() { - return Collections.unmodifiableList(stopSequences); - } - - /** - * The token selection biases to use for prompt execution. The key is the token id from the - * tokenizer, and the value is the bias. A negative bias will make the model less likely to use - * the token, and a positive bias will make the model more likely to use the token. - * - * @return The token selection biases to use for prompt execution. - */ - @JsonProperty(TOKEN_SELECTION_BIASES) - public Map getTokenSelectionBiases() { - return Collections.unmodifiableMap(tokenSelectionBiases); - } - - @Override - public int hashCode() { - return Objects.hash(serviceId, modelId, temperature, topP, presencePenalty, - frequencyPenalty, - maxTokens, bestOf, resultsPerPrompt, user, stopSequences, tokenSelectionBiases, - responseFormat); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!getClass().isInstance(obj)) { - return false; - } - - PromptExecutionSettings other = (PromptExecutionSettings) obj; - - if (!Objects.equals(serviceId, other.serviceId)) { - return false; - } - if (!Objects.equals(modelId, other.modelId)) { - return false; - } - if (Double.compare(temperature, other.temperature) != 0) { - return false; - } - if (Double.compare(topP, other.topP) != 0) { - return false; - } - if (Double.compare(presencePenalty, other.presencePenalty) != 0) { - return false; - } - if (Double.compare(frequencyPenalty, other.frequencyPenalty) != 0) { - return false; - } - if (maxTokens != other.maxTokens) { - return false; - } - if (bestOf != other.bestOf) { - return false; - } - if (resultsPerPrompt != other.resultsPerPrompt) { - return false; - } - if (!Objects.equals(user, other.user)) { - return false; - } - if (!Objects.equals(stopSequences, other.stopSequences)) { - return false; - } - if (!Objects.equals(responseFormat, other.responseFormat)) { - return false; - } - return Objects.equals(tokenSelectionBiases, other.tokenSelectionBiases); - } - - /** - * The response format to use for prompt execution. Currently this only applies to chat - * completions. - * - * @return The response format to use for prompt execution. - */ - @JsonProperty(RESPONSE_FORMAT) - public ResponseFormat getResponseFormat() { - return responseFormat; - } - - /** - * Builder for PromptExecutionSettings. - */ - public static class Builder { - - Map settings = new HashMap<>(); - - /** - * Set the id of the AI service to use for prompt execution. - * - * @param serviceId The id of the AI service to use for prompt execution. - * @return This builder. - */ - public Builder withServiceId(String serviceId) { - settings.put(SERVICE_ID, serviceId); - return this; - } - - /** - * Set the id of the model to use for prompt execution. - * - * @param modelId The id of the model to use for prompt execution. - * @return This builder. - */ - public Builder withModelId(String modelId) { - settings.put(MODEL_ID, modelId); - return this; - } - - /** - * Set the temperature setting for prompt execution. The value is clamped to the range [0.0, - * 2.0], and the default is 1.0. - * - * @param temperature The temperature setting for prompt execution. - * @return This builder. - */ - public Builder withTemperature(double temperature) { - if (!Double.isNaN(temperature)) { - settings.put(TEMPERATURE, temperature); - } - return this; - } - - /** - * Set the topP setting for prompt execution. The value is clamped to the range [0.0, 1.0], - * and the default is 1.0. - * - * @param topP The topP setting for prompt execution. - * @return This builder. - */ - public Builder withTopP(double topP) { - if (!Double.isNaN(topP)) { - settings.put(TOP_P, topP); - } - return this; - } - - /** - * Set the presence penalty setting for prompt execution. The value is clamped to the range - * [-2.0, 2.0], and the default is 0.0. - * - * @param presencePenalty The presence penalty setting for prompt execution. - * @return This builder. - */ - public Builder withPresencePenalty(double presencePenalty) { - if (!Double.isNaN(presencePenalty)) { - settings.put(PRESENCE_PENALTY, presencePenalty); - } - return this; - } - - /** - * Set the frequency penalty setting for prompt execution. The value is clamped to the range - * [-2.0, 2.0], and the default is 0.0. - * - * @param frequencyPenalty The frequency penalty setting for prompt execution. - * @return This builder. - */ - public Builder withFrequencyPenalty(double frequencyPenalty) { - if (!Double.isNaN(frequencyPenalty)) { - settings.put(FREQUENCY_PENALTY, frequencyPenalty); - } - return this; - } - - /** - * Set the maximum number of tokens to generate in the output. The value is clamped to the - * range [1, Integer.MAX_VALUE], and the default is 256. - * - * @param maxTokens The maximum number of tokens to generate in the output. - * @return This builder. - */ - public Builder withMaxTokens(int maxTokens) { - settings.put(MAX_TOKENS, maxTokens); - return this; - } - - /** - * Set the number of results to generate for each prompt. The value is clamped to the range - * [1, Integer.MAX_VALUE], and the default is 1. - * - * @param resultsPerPrompt The number of results to generate for each prompt. - * @return This builder. - */ - public Builder withResultsPerPrompt(int resultsPerPrompt) { - settings.put(RESULTS_PER_PROMPT, resultsPerPrompt); - return this; - } - - /** - * Set the best of setting for prompt execution. The value is clamped to the range [1, - * Integer.MAX_VALUE], and the default is 1. - * - * @param bestOf The best of setting for prompt execution. - * @return This builder. - */ - public Builder withBestOf(int bestOf) { - settings.put(BEST_OF, bestOf); - return this; - } - - /** - * Set the user to associate with the prompt execution. - * - * @param user The user to associate with the prompt execution. - * @return This builder. - */ - public Builder withUser(String user) { - settings.put(USER, user); - return this; - } - - /** - * Set the stop sequences to use for prompt execution. - * - * @param stopSequences The stop sequences to use for prompt execution. - * @return This builder. - */ - @SuppressWarnings("unchecked") - public Builder withStopSequences(List stopSequences) { - if (stopSequences != null) { - ((List) settings.computeIfAbsent(STOP_SEQUENCES, - k -> new ArrayList<>())).addAll(stopSequences); - } - return this; - } - - /** - * Set the token selection biases to use for prompt execution. The bias values are clamped - * to the range [-100, 100]. - * - * @param tokenSelectionBiases The token selection biases to use for prompt execution. - * @return This builder. - */ - @SuppressWarnings("unchecked") - public Builder withTokenSelectionBiases(Map tokenSelectionBiases) { - if (tokenSelectionBiases != null) { - ((Map) settings.computeIfAbsent(TOKEN_SELECTION_BIASES, - k -> new HashMap<>())).putAll(tokenSelectionBiases); - } - return this; - } - - /** - * Set the response format to use for prompt execution. - * - * @param responseFormat The response format to use for prompt execution. - * @return This builder. - */ - public Builder withResponseFormat(ResponseFormat responseFormat) { - if (responseFormat != null) { - settings.put(RESPONSE_FORMAT, responseFormat); - } - return this; - } - - /** - * Set the response format to use for prompt execution. - * - * @param responseFormat The response format to use for prompt execution. - * @return This builder. - */ - public Builder withResponseFormat(ResponseFormat.Type responseFormat) { - switch (responseFormat) { - case JSON_OBJECT: - settings.put(RESPONSE_FORMAT, new JsonObjectResponseFormat()); - break; - case TEXT: - settings.put(RESPONSE_FORMAT, new TextResponseFormat()); - break; - case JSON_SCHEMA: - throw new SKException( - "Cannot set JSON_SCHEMA response format without a schema, use withResponseFormat(ResponseFormat responseFormat)"); - } - - return this; - } - - /** - * Set the response format to use a json schema generated for the given class. The name of - * the response format will be the name of the class. - * - * @param responseFormat The response format type. - * @return This builder. - */ - public Builder withJsonSchemaResponseFormat(Class responseFormat) { - if (responseFormat != null) { - settings.put(RESPONSE_FORMAT, - JsonSchemaResponseFormat.builder() - .setResponseFormat(responseFormat) - .setName(responseFormat.getSimpleName()) - .build()); - } - return this; - } - - /** - * Build the PromptExecutionSettings. - * - * @return A new PromptExecutionSettings from this builder. - */ - @SuppressWarnings("unchecked") - public PromptExecutionSettings build() { - return new PromptExecutionSettings( - (String) settings.getOrDefault(SERVICE_ID, DEFAULT_SERVICE_ID), - (String) settings.getOrDefault(MODEL_ID, ""), - (Double) settings.getOrDefault(TEMPERATURE, DEFAULT_TEMPERATURE), - (Double) settings.getOrDefault(TOP_P, DEFAULT_TOP_P), - (Double) settings.getOrDefault(PRESENCE_PENALTY, DEFAULT_PRESENCE_PENALTY), - (Double) settings.getOrDefault(FREQUENCY_PENALTY, DEFAULT_FREQUENCY_PENALTY), - (Integer) settings.getOrDefault(MAX_TOKENS, DEFAULT_MAX_TOKENS), - (Integer) settings.getOrDefault(RESULTS_PER_PROMPT, DEFAULT_RESULTS_PER_PROMPT), - (Integer) settings.getOrDefault(BEST_OF, DEFAULT_BEST_OF), - (String) settings.getOrDefault(USER, ""), - (List) settings.getOrDefault(STOP_SEQUENCES, Collections.emptyList()), - (Map) settings.getOrDefault(TOKEN_SELECTION_BIASES, - Collections.emptyMap()), - (ResponseFormat) settings.getOrDefault(RESPONSE_FORMAT, new TextResponseFormat())); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ToolCallBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ToolCallBehavior.java deleted file mode 100644 index 6454a7fdb..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ToolCallBehavior.java +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import javax.annotation.Nullable; - -/** - * Defines the behavior of a tool call. Currently, the only tool available is function calling. - */ -public class ToolCallBehavior { - - /** - * Allow all kernel functions. All Kernel functions will be passed to the model. - * - * @param autoInvoke Enable or disable auto-invocation. - * If auto-invocation is enabled, the model may request that the Semantic Kernel - * invoke the kernel functions and return the value to the model. - * @return A new ToolCallBehavior instance with all kernel functions allowed. - */ - public static ToolCallBehavior allowAllKernelFunctions(boolean autoInvoke) { - return new AllowedKernelFunctions(true, autoInvoke, null); - } - - /** - * Require a function. The required function will be the only function passed to the model - * and forces the model to call the function. Only one function can be required. - * - * @param function The function to require. - * @return A new ToolCallBehavior instance with the required function. - */ - public static ToolCallBehavior requireKernelFunction(KernelFunction function) { - return new RequiredKernelFunction(function); - } - - /** - * Allow a set of kernel functions. - * If a function is allowed, it may be called. If it is not allowed, it will not be called. - * By default, all functions are not allowed. - * - * @param autoInvoke Enable or disable auto-invocation. - * If auto-invocation is enabled, the model may request that the Semantic Kernel - * invoke the kernel functions and return the value to the model. - * @param functions The functions to allow. - * @return A new ToolCallBehavior instance with the allowed functions. - */ - public static ToolCallBehavior allowOnlyKernelFunctions(boolean autoInvoke, - List> functions) { - return new AllowedKernelFunctions(false, autoInvoke, functions); - } - - /** - * Allow a set of kernel functions. - * If a function is allowed, it may be called. If it is not allowed, it will not be called. - * By default, all functions are not allowed. - * - * @param autoInvoke Enable or disable auto-invocation. - * If auto-invocation is enabled, the model may request that the Semantic Kernel - * invoke the kernel functions and return the value to the model. - * @param functions The functions to allow. - * @return A new ToolCallBehavior instance with the allowed functions. - */ - public static ToolCallBehavior allowOnlyKernelFunctions(boolean autoInvoke, - KernelFunction... functions) { - return allowOnlyKernelFunctions(autoInvoke, Arrays.asList(functions)); - } - - private static final int DEFAULT_MAXIMUM_AUTO_INVOKE_ATTEMPTS = 5; - /** - * The separator between the plugin name and the function name. - */ - public static final String FUNCTION_NAME_SEPARATOR = "-"; - private final int maximumAutoInvokeAttempts; - - /** - * Create a new instance of ToolCallBehavior - */ - private ToolCallBehavior(int maximumAutoInvokeAttempts) { - this.maximumAutoInvokeAttempts = maximumAutoInvokeAttempts; - } - - /** - * Check whether auto-invocation is enabled. - * - * @return Whether auto-invocation is enabled. - */ - public boolean isAutoInvokeAllowed() { - return maximumAutoInvokeAttempts > 0; - } - - /** - * Get the maximum number of times that auto-invocation will be attempted. - * - * @return The maximum number of attempts. - */ - public int getMaximumAutoInvokeAttempts() { - return this.maximumAutoInvokeAttempts; - } - - /** - * Form the full function name. - * - * @param pluginName The name of the plugin that the function is in. - * @param functionName The name of the function. - * @return The key for the function. - */ - public static String formFullFunctionName(@Nullable String pluginName, String functionName) { - if (pluginName == null) { - pluginName = ""; - } - return String.format("%s%s%s", pluginName, FUNCTION_NAME_SEPARATOR, functionName); - } - - /** - * A required kernel function. - * The required function will be the only function passed to the model and forces the model to call the function. - * Only one function can be required. - */ - public static class RequiredKernelFunction extends ToolCallBehavior { - private final KernelFunction requiredFunction; - - /** - * Create a new instance of RequiredKernelFunction. - * - * @param requiredFunction The function that is required. - */ - public RequiredKernelFunction(KernelFunction requiredFunction) { - super(1); - this.requiredFunction = requiredFunction; - } - - /** - * Get the required function. - * @return the required function. - */ - public KernelFunction getRequiredFunction() { - return requiredFunction; - } - } - - /** - * A set of allowed kernel functions. All kernel functions are allowed if allKernelFunctionsAllowed is true. - * Otherwise, only the functions in allowedFunctions are allowed. - *

- * If a function is allowed, it may be called. If it is not allowed, it will not be called. - */ - public static class AllowedKernelFunctions extends ToolCallBehavior { - private final Set allowedFunctions; - private final boolean allKernelFunctionsAllowed; - - /** - * Create a new instance of AllowedKernelFunctions. - * - * @param allKernelFunctionsAllowed Whether all kernel functions are allowed. - * @param autoInvoke Whether auto-invocation is enabled. - * @param allowedFunctions A set of functions that are allowed. - */ - public AllowedKernelFunctions(boolean allKernelFunctionsAllowed, boolean autoInvoke, - @Nullable List> allowedFunctions) { - super(autoInvoke ? DEFAULT_MAXIMUM_AUTO_INVOKE_ATTEMPTS : 0); - this.allKernelFunctionsAllowed = allKernelFunctionsAllowed; - this.allowedFunctions = new HashSet<>(); - if (allowedFunctions != null) { - allowedFunctions.stream().filter(Objects::nonNull).forEach( - f -> this.allowedFunctions - .add(formFullFunctionName(f.getPluginName(), f.getName()))); - } - } - - /** - * Check whether the given function is allowed. - * - * @param function The function to check. - * @return Whether the function is allowed. - */ - public boolean isFunctionAllowed(KernelFunction function) { - return isFunctionAllowed(function.getPluginName(), function.getName()); - } - - /** - * Check whether the given function is allowed. - * - * @param pluginName The name of the skill that the function is in. - * @param functionName The name of the function. - * @return Whether the function is allowed. - */ - public boolean isFunctionAllowed(@Nullable String pluginName, String functionName) { - String key = formFullFunctionName(pluginName, functionName); - return allowedFunctions.contains(key); - } - - /** - * Check whether all kernel functions are allowed. - * - * @return Whether all kernel functions are allowed. - */ - public boolean isAllKernelFunctionsAllowed() { - return allKernelFunctionsAllowed; - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonObjectResponseFormat.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonObjectResponseFormat.java deleted file mode 100644 index dde82691e..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonObjectResponseFormat.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.fasterxml.jackson.annotation.JsonCreator; - -/** - * A response represented in a JSON format. - */ -public class JsonObjectResponseFormat extends ResponseFormat { - - /** - * Used by Jackson deserialization to create a new instance - * of the {@link JsonObjectResponseFormat} class. - */ - @JsonCreator - public JsonObjectResponseFormat() { - super(Type.JSON_OBJECT); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonResponseSchema.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonResponseSchema.java deleted file mode 100644 index c952cfea7..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonResponseSchema.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * The schema for a response in JSON format. - */ -public class JsonResponseSchema extends ResponseSchema { - - private final String name; - private final String schema; - private final boolean strict; - - /** - * Used by Jackson deserialization to create a new - * instance of the {@link JsonResponseSchema} class. - * - * @param name The name of the schema. - * @param schema The schema. - * @param strict Whether the schema is strict. - */ - @JsonCreator - public JsonResponseSchema( - @JsonProperty("name") String name, - @JsonProperty("schema") String schema, - @JsonProperty("strict") boolean strict) { - this.name = name; - this.schema = schema; - this.strict = strict; - } - - /** - * Gets the name of the schema. - * @return The name of the schema. - */ - public String getName() { - return name; - } - - /** - * Gets the schema. - * @return The schema. - */ - public String getSchema() { - return schema; - } - - /** - * Gets whether the schema is strict. - * @return Whether the schema is strict. - */ - public boolean isStrict() { - return strict; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonSchemaResponseFormat.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonSchemaResponseFormat.java deleted file mode 100644 index ebc43b93b..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/JsonSchemaResponseFormat.java +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.exceptions.SKException; -import javax.annotation.Nullable; - -/** - * A response represented in a JSON schema format. - */ -public class JsonSchemaResponseFormat extends ResponseFormat { - - private final JsonResponseSchema jsonSchema; - - /** - * Used by Jackson deserialization to create a new instance - * of the {@link JsonSchemaResponseFormat} class. - * @param jsonSchema The JSON schema. - */ - @JsonCreator - public JsonSchemaResponseFormat( - @JsonProperty("json_schema") JsonResponseSchema jsonSchema) { - super(Type.JSON_SCHEMA); - this.jsonSchema = jsonSchema; - } - - /** - * Gets the JSON schema. - * @return The JSON schema. - */ - @JsonProperty("json_schema") - public JsonResponseSchema getJsonSchema() { - return jsonSchema; - } - - /** - * Creates a new instance of the {@link JsonSchemaResponseFormat} class. - * @return The new instance. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for the {@link JsonSchemaResponseFormat} class. - */ - public static class Builder { - - @Nullable - private JsonResponseSchema jsonResponseSchema = null; - @Nullable - private String jsonSchema = null; - @Nullable - private String name = null; - private boolean strict = true; - - /** - * Sets the response format. - * @param clazz The class. - * @param responseSchemaGenerator The response schema generator. - * @return The builder. - */ - public Builder setResponseFormat(Class clazz, - ResponseSchemaGenerator responseSchemaGenerator) { - name = clazz.getSimpleName(); - return setJsonSchema(responseSchemaGenerator.generateSchema(clazz)); - } - - /** - * Sets the response format. Uses Jackson to generate the schema - * from the {@code clazz} - * @param clazz The class. - * @return The builder. - */ - public Builder setResponseFormat(Class clazz) { - name = clazz.getSimpleName(); - setJsonSchema(ResponseSchemaGenerator.jacksonGenerator().generateSchema(clazz)); - return this; - } - - /** - * Sets the JSON response schema. - * @param jsonResponseSchema The JSON response schema. - * @return The builder. - */ - public Builder setJsonResponseSchema(JsonResponseSchema jsonResponseSchema) { - this.jsonResponseSchema = jsonResponseSchema; - return this; - } - - /** - * Sets the JSON schema. - * @param jsonSchema The JSON schema. - * @return The builder. - */ - public Builder setJsonSchema(String jsonSchema) { - this.jsonSchema = jsonSchema; - return this; - } - - /** - * Sets the name of the JSON schema. - * @param name The schema name. - * @return The builder. - */ - public Builder setName(String name) { - this.name = name; - return this; - } - - /** - * Sets whether the schema is strict. - * @param strict Whether the schema is strict. - * @return The builder. - */ - public Builder setStrict(boolean strict) { - this.strict = strict; - return this; - } - - /** - * Builds the {@link JsonSchemaResponseFormat} instance. - * @return The {@link JsonSchemaResponseFormat} instance. - */ - public JsonSchemaResponseFormat build() { - - if (jsonResponseSchema != null) { - return new JsonSchemaResponseFormat(jsonResponseSchema); - } - - if (jsonSchema == null) { - throw new SKException("Response format not set"); - } - - if (name == null) { - throw new SKException("Json format name not set"); - } - - return new JsonSchemaResponseFormat(new JsonResponseSchema(name, jsonSchema, strict)); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseFormat.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseFormat.java deleted file mode 100644 index 9ebcbd660..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseFormat.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeInfo.As; -import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; - -/** - * Base class for response formats. - */ -@JsonTypeInfo(use = Id.NAME, include = As.EXISTING_PROPERTY, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(value = JsonSchemaResponseFormat.class, name = "json_schema", names = { - "json_schema", "JSON_SCHEMA" }), - @JsonSubTypes.Type(value = TextResponseFormat.class, name = "text", names = { "text", - "TEXT" }), - @JsonSubTypes.Type(value = JsonObjectResponseFormat.class, name = "json_object", names = { - "json_object", "JSON_OBJECT" }), - -}) -public abstract class ResponseFormat { - - /** - * The type of the response format. - */ - public static enum Type { - /** - * Only valid for openai chat completion, with GPT-4 and gpt-3.5-turbo-1106+ models. - */ - JSON_OBJECT, - /** - * Only valid for openai chat completion, with GPT-4 and gpt-3.5-turbo-1106+ models. - */ - JSON_SCHEMA, - /** - * The response is in text format. - */ - TEXT; - } - - private final Type type; - - /** - * Creates a new instance of the {@link ResponseFormat} class. - * - * @param type The type of the response format. - */ - public ResponseFormat(Type type) { - this.type = type; - } - - /** - * Gets the type of the response format. - * - * @return The type. - */ - @JsonProperty("type") - public Type getType() { - return type; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchema.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchema.java deleted file mode 100644 index 5d1403305..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchema.java +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -public abstract class ResponseSchema { - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchemaGenerator.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchemaGenerator.java deleted file mode 100644 index 676f2872d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/ResponseSchemaGenerator.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.ServiceLoadUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Interface for generating json response schemas for a given class. - */ -public interface ResponseSchemaGenerator { - - Logger LOGGER = LoggerFactory.getLogger(ResponseSchemaGenerator.class); - - /** - * Generate a json schema for the given class. - * - * @param clazz The class to generate a schema for. - * @return The json schema. - */ - public String generateSchema(Class clazz); - - /** - * Load a response schema generator based on the Jackson library, requires that - * com.github.victools:jsonschema-generator has been added to the class path. - * - * @return The response schema generator. - */ - public static ResponseSchemaGenerator jacksonGenerator() { - try { - return loadGenerator( - "com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat.JacksonResponseFormatGenerator"); - } catch (NoClassDefFoundError e) { - LOGGER.error( - "The Jackson response schema generator relies on the optional dependencies 'com.github.victools:jsonschema-generator', and 'com.github.victools:jsonschema-module-jackson'. To use this feature, please add this dependency to your project."); - throw new SKException( - "The Jackson response schema generator relies on the optional dependency 'com.github.victools:jsonschema-generator', and 'com.github.victools:jsonschema-module-jackson'. To use this feature, please add this dependency to your project."); - } - } - - /** - * Load a response schema generator based on the given class name. - * The class must implement the {@link ResponseSchemaGenerator} interface. - * - * @param className The class name of the generator. - * @return The response schema generator. - */ - public static ResponseSchemaGenerator loadGenerator(String className) { - return ServiceLoadUtil - .findServiceLoader(ResponseSchemaGenerator.class, - className) - .get(); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/TextResponseFormat.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/TextResponseFormat.java deleted file mode 100644 index 45214f31e..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/responseformat/TextResponseFormat.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration.responseformat; - -import com.fasterxml.jackson.annotation.JsonCreator; - -/** - * Represents a text response format. - */ -public class TextResponseFormat extends ResponseFormat { - - /** - * Used by Jackson to creates a new instance of the - * {@link TextResponseFormat} class. - */ - @JsonCreator - public TextResponseFormat() { - super(Type.TEXT); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPlugin.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPlugin.java deleted file mode 100644 index e23495813..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPlugin.java +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.plugin; - -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * A plugin contains a collection of functions that can be invoked by the Semantic Kernel. - */ -public class KernelPlugin implements Iterable> { - - private final String name; - @Nullable - private final String description; - - private final CaseInsensitiveMap> functions; - - /** - * Creates a new instance of the {@link KernelPlugin} class. - * - * @param name The name of the plugin. - * @param description The description of the plugin. - * @param plugins The functions in the plugin. - */ - public KernelPlugin( - String name, - @Nullable String description, - Map> plugins) { - this.name = name; - this.description = description; - this.functions = new CaseInsensitiveMap<>(); - if (plugins != null) { - this.functions.putAll(plugins); - } - } - - /** - * Adds a function to the plugin. - * - * @param function The function to add. - */ - public void addFunction(KernelFunction function) { - functions.put(function.getName(), function); - } - - /** - * Gets the functions in the plugin. - * - * @return The functions in the plugin. - */ - public Map> getFunctions() { - return Collections.unmodifiableMap(functions); - } - - /** - * Gets a function by name. - * - * @param functionName The name of the function. - * @param The return type of the function. - * @return The function with the specified name, or {@code null} if no such function exists. - */ - @Nullable - @SuppressWarnings("unchecked") - public KernelFunction get(String functionName) { - return (KernelFunction) functions.get(functionName); - } - - /** - * Get an {@code Iterator} that iterates over the functions of this plugin. - * - * @return An {@code Iterator} that iterates over the functions of this plugin. - */ - @Override - public Iterator> iterator() { - return functions.values().iterator(); - } - - /** - * Gets the name of the plugin. - * - * @return The name of the plugin. - */ - public String getName() { - return name; - } - - /** - * Gets the description of the plugin. - * - * @return The description of the plugin. - */ - @Nullable - public String getDescription() { - return description; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java deleted file mode 100644 index afa31cb00..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java +++ /dev/null @@ -1,555 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.plugin; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader; -import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader.ResourceLocation; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.InputVariable; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod; -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt; -import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.OutputVariable; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.reactivestreams.Publisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Factory for creating {@link KernelPlugin} instances. {@code KernelPlugin}s can be created from a - * Java object, from loading a directory of plugins, or from loading plugins from a resource. - */ -public class KernelPluginFactory { - - private static final Logger LOGGER = LoggerFactory.getLogger(KernelPluginFactory.class); - private static final String CONFIG_FILE = "config.json"; - private static final String PROMPT_FILE = "skprompt.txt"; - private static final CaseInsensitiveMap> PRIMITIVE_CLASS_NAMES = new CaseInsensitiveMap<>(); - private static final CaseInsensitiveMap> COMMON_CLASS_NAMES = new CaseInsensitiveMap<>(); - private static final Map, Class> BOXED_FROM_PRIMITIVE = new HashMap<>(); - - static { - PRIMITIVE_CLASS_NAMES.put("void", void.class); - PRIMITIVE_CLASS_NAMES.put("int", int.class); - PRIMITIVE_CLASS_NAMES.put("double", double.class); - PRIMITIVE_CLASS_NAMES.put("boolean", boolean.class); - PRIMITIVE_CLASS_NAMES.put("float", float.class); - PRIMITIVE_CLASS_NAMES.put("long", long.class); - PRIMITIVE_CLASS_NAMES.put("short", short.class); - PRIMITIVE_CLASS_NAMES.put("byte", byte.class); - PRIMITIVE_CLASS_NAMES.put("char", char.class); - - COMMON_CLASS_NAMES.put("integer", int.class); - COMMON_CLASS_NAMES.put("string", String.class); - COMMON_CLASS_NAMES.put("list", ArrayList.class); - COMMON_CLASS_NAMES.put("map", HashMap.class); - COMMON_CLASS_NAMES.put("set", HashSet.class); - - BOXED_FROM_PRIMITIVE.put(void.class, Void.class); - BOXED_FROM_PRIMITIVE.put(int.class, Integer.class); - BOXED_FROM_PRIMITIVE.put(double.class, Double.class); - BOXED_FROM_PRIMITIVE.put(boolean.class, Boolean.class); - BOXED_FROM_PRIMITIVE.put(float.class, Float.class); - BOXED_FROM_PRIMITIVE.put(long.class, Long.class); - BOXED_FROM_PRIMITIVE.put(short.class, Short.class); - BOXED_FROM_PRIMITIVE.put(byte.class, Byte.class); - BOXED_FROM_PRIMITIVE.put(char.class, Character.class); - - } - - /** - * Creates a plugin that wraps the specified target object. Methods decorated with - * {@code {@literal @}DefineSKFunction} will be included in the plugin. - * - * @param target The instance of the class to be wrapped. - * @param pluginName Name of the plugin for function collection and prompt templates. If the - * value is {@code null}, a plugin name is derived from the type of the - * target. - * @return The new plugin. - */ - public static KernelPlugin createFromObject(Object target, String pluginName) { - Class clazz = target.getClass(); - return KernelPluginFactory.createFromObject(clazz, target, pluginName); - } - - /** - * Creates a plugin that wraps the specified target object. Methods decorated with - * {@code {@literal @}DefineSKFunction} will be included in the plugin. - * - * @param clazz The class to be wrapped. - * @param target The instance of the class to be wrapped. - * @param pluginName Name of the plugin for function collection and prompt templates. If the - * value is {@code null}, a plugin name is derived from the type of the - * target. - * @return The new plugin. - */ - public static KernelPlugin createFromObject(Class clazz, Object target, String pluginName) { - if (!clazz.isInstance(target)) { - throw new SKException("Target object is not an instance of the provided class"); - } - - List> methods = Arrays.stream(clazz.getMethods()) - .filter(method -> method.isAnnotationPresent(DefineKernelFunction.class)) - .map(method -> { - DefineKernelFunction annotation = method.getAnnotation(DefineKernelFunction.class); - Class returnType = getReturnType(annotation, method); - OutputVariable kernelReturnParameterMetadata = new OutputVariable<>( - annotation.returnDescription(), - returnType); - - KernelFunctionFromMethod.Builder builder = KernelFunction - .createFromMethod(method, target) - .withParameters(getParameters(method)) - .withReturnParameter(kernelReturnParameterMetadata); - - if (pluginName != null && !pluginName.isEmpty()) { - builder = builder.withPluginName(pluginName); - } - - if (annotation.name() != null && !annotation.name().isEmpty()) { - builder = builder.withFunctionName(annotation.name()); - } - - if (annotation.description() != null && !annotation.description().isEmpty()) { - builder = builder.withDescription(annotation.description()); - } - - return builder.build(); - - }).collect(ArrayList::new, (list, it) -> list.add(it), (a, b) -> a.addAll(b)); - - KernelPlugin plugin = createFromFunctions(pluginName, methods); - - if (plugin.getFunctions().isEmpty()) { - LOGGER.warn( - SemanticKernelResources.getString( - "no.functions.found.in.class.this.can.be.caused.by"), - clazz.getName()); - } - return plugin; - } - - private static Class getReturnType(DefineKernelFunction annotation, Method method) { - Class returnType = null; - if (annotation.returnType().isEmpty()) { - returnType = method.getReturnType(); - - if (Publisher.class.isAssignableFrom(returnType)) { - throw new SKException( - "Method: " + method.getDeclaringClass().getName() + "." + method.getName() - + ", this is an async method, It is required to add an annotation to specify the return type"); - } - } else { - String className = annotation.returnType(); - if (method.getReturnType().getName().equals(className)) { - // primarily meant to handle void - return method.getReturnType(); - } - - try { - returnType = Thread.currentThread().getContextClassLoader() - .loadClass(annotation.returnType()); - } catch (ClassNotFoundException e) { - // ignore - } - - if (returnType == null) { - returnType = getCommonTypeAlias(method, className); - } - - if (returnType == null) { - throw new SKException("Could not find return type " + annotation.returnType() - + " is not found on method " + method.getDeclaringClass().getName() + "." - + method.getName()); - } - - if (!Publisher.class.isAssignableFrom(method.getReturnType()) - && !returnType.isAssignableFrom(method.getReturnType())) { - throw new SKException( - "Return type " + returnType.getName() + " is not assignable from " - + method.getReturnType()); - } - } - - return returnType; - } - - /** - * Returns a class found via an inexact match on the class name, i.e does not require the user - * to provide a fully qualified class name for common types. - * - * @param method The method to get the return type for. - * @param className The class name to search for. - * @return The class if found, otherwise null. - */ - @Nullable - private static Class getCommonTypeAlias(Method method, String className) { - Class returnType = PRIMITIVE_CLASS_NAMES.get(className); - - if (returnType == null) { - returnType = COMMON_CLASS_NAMES.get(className); - } - - if (returnType != null && Publisher.class.isAssignableFrom(method.getReturnType())) { - return returnType; - } - - if (returnType != null && !returnType.isAssignableFrom(method.getReturnType())) { - returnType = BOXED_FROM_PRIMITIVE.get(returnType); - } - - return returnType; - } - - /** - * Returns the class for the provided type name. - * - * @param className The type name. - * @return The class for the type name. - */ - public static Class getTypeForName(String className) { - Class clazz = PRIMITIVE_CLASS_NAMES.get(className); - - if (clazz == null) { - clazz = COMMON_CLASS_NAMES.get(className); - } - - if (clazz != null) { - return clazz; - } - - try { - clazz = Thread.currentThread().getContextClassLoader().loadClass(className); - } catch (ClassNotFoundException e) { - // ignore - } - - if (clazz == null) { - try { - // Seems that in tests specifically we need to use the class loader of the class itself - clazz = KernelPluginFactory.class.getClassLoader().loadClass(className); - } catch (ClassNotFoundException e) { - // ignore - } - } - - if (clazz == null) { - throw new SKException("Requested type could not be found: " + className - + ". This needs to be a fully qualified class name, e.g. 'java.lang.String'."); - } - return clazz; - } - - /** - * Creates a plugin from the provided name and function collection. - * - * @param pluginName The name for the plugin. - * @param functions The initial functions to be available as part of the plugin. - * @return The new plugin. - */ - public static KernelPlugin createFromFunctions( - String pluginName, - @Nullable List> functions) { - return createFromFunctions(pluginName, null, functions); - } - - /** - * Initializes the new plugin from the provided name, description, and function collection. - * - * @param pluginName The name for the plugin. - * @param description A description of the plugin. - * @param functions The initial functions to be available as part of the plugin. - * @return The new plugin. - */ - public static KernelPlugin createFromFunctions(String pluginName, @Nullable String description, - @Nullable List> functions) { - Map> funcs = new HashMap<>(); - if (functions != null) { - funcs = functions.stream().collect(Collectors.toMap(KernelFunction::getName, f -> f)); - } - return new KernelPlugin(pluginName, description, funcs); - } - - private static List getParameters(Method method) { - return Arrays.stream(method.getParameters()) - .filter(parameter -> parameter.isAnnotationPresent(KernelFunctionParameter.class)) - .map(parameter -> { - KernelFunctionParameter annotation = parameter.getAnnotation( - KernelFunctionParameter.class); - - List enumValues = KernelFunctionFromMethod - .getEnumOptions(annotation.type()); - - return InputVariable.build( - annotation.name(), - annotation.type(), - annotation.description(), - annotation.defaultValue(), - enumValues, - annotation.required()); - }).collect(Collectors.toList()); - } - - /** - * Imports a plugin from a directory. The directory should contain subdirectories, each of which - * contains a prompt template and a configuration file. The configuration file should be named - * "config.json" and the prompt template should be named "skprompt.txt". - * - * @param parentDirectory The parent directory containing the plugin directories. - * @param pluginDirectoryName The name of the plugin directory. - * @param promptTemplateFactory The factory to use for creating prompt templates. - * @return The imported plugin. - */ - public static KernelPlugin importPluginFromDirectory( - Path parentDirectory, - String pluginDirectoryName, - @Nullable PromptTemplateFactory promptTemplateFactory) { - - // Verify.ValidSkillName(pluginDirectoryName); - File pluginDir = new File(parentDirectory.toFile(), pluginDirectoryName); - // Verify.DirectoryExists(pluginDir); - if (!pluginDir.exists() || !pluginDir.isDirectory()) { - throw new SKException("Could not find directory " + pluginDir.getAbsolutePath()); - } - File[] files = pluginDir.listFiles(File::isDirectory); - if (files == null) { - throw new SKException("No Plugins found in directory " + pluginDir.getAbsolutePath()); - } - - Map> plugins = new CaseInsensitiveMap<>(); - - for (File dir : files) { - try { - // Continue only if prompt template exists - File promptPath = new File(dir, PROMPT_FILE); - if (!promptPath.exists()) { - continue; - } - - File configPath = new File(dir, CONFIG_FILE); - if (!configPath.exists()) { - continue; - // Verify.NotNull(config, $"Invalid prompt template - // configuration, unable to parse {configPath}"); - } - - KernelFunction plugin = getKernelFunction(dir.getName(), promptTemplateFactory, - configPath, - promptPath); - - plugins.put(dir.getName(), plugin); - } catch (IOException e) { - LOGGER.error(SemanticKernelResources.getString("failed.to.read.file"), e); - } - } - - return new KernelPlugin( - pluginDirectoryName, - null, - plugins); - } - - private static KernelFunction getKernelFunction( - @Nullable String functionName, - @Nullable PromptTemplateFactory promptTemplateFactory, - File configPath, - File promptPath) - throws IOException { - try { - PromptTemplateConfig config = new ObjectMapper().readValue(configPath, - PromptTemplateConfig.class); - - // Load prompt template - String template = new String(Files.readAllBytes(promptPath.toPath()), - Charset.defaultCharset()); - - return getKernelFunction(functionName, promptTemplateFactory, config, template); - } catch (Exception e) { - LOGGER.error(SemanticKernelResources.getString("failed.to.read.file1"), - configPath.getAbsolutePath(), e); - - throw new SKException("Failed to read function " + configPath.getAbsolutePath(), e); - } - } - - @SuppressWarnings("unchecked") - private static KernelFunction getKernelFunction( - @Nullable String functionName, - @Nullable PromptTemplateFactory promptTemplateFactory, - PromptTemplateConfig config, - String template) { - PromptTemplate promptTemplate; - - config = config.copy().withTemplate(template).build(); - - if (promptTemplateFactory != null) { - promptTemplate = promptTemplateFactory.tryCreate(config); - } else { - promptTemplate = new KernelPromptTemplateFactory().tryCreate(config); - } - - if (config.getName() != null) { - functionName = config.getName(); - } - - return (KernelFunction) new KernelFunctionFromPrompt.Builder<>() - .withName(functionName) - .withDescription(config.getDescription()) - .withExecutionSettings(config.getExecutionSettings()) - .withInputParameters(config.getInputVariables()) - .withPromptTemplate(promptTemplate) - .withTemplate(template) - .withTemplateFormat(config.getTemplateFormat()) - .withOutputVariable(config.getOutputVariable()) - .withPromptTemplateFactory(promptTemplateFactory) - .build(); - } - - /** - * Imports a plugin from a resource directory on the filesystem. - * @param parentDirectory The parent directory containing the plugin directories. - * @param pluginDirectoryName The name of the plugin directory. - * @param functionName The name of the function to import. - * @param promptTemplateFactory The factory to use for creating prompt templates. - * @return The imported plugin. - * @see KernelPluginFactory#importPluginFromResourcesDirectory(String, String, String, - * PromptTemplateFactory, Class) - */ - @Nullable - public static KernelPlugin importPluginFromResourcesDirectory( - String parentDirectory, - String pluginDirectoryName, - String functionName, - @Nullable PromptTemplateFactory promptTemplateFactory) { - return importPluginFromResourcesDirectory(parentDirectory, pluginDirectoryName, - functionName, - promptTemplateFactory, null); - } - - /** - * Imports a plugin from a resource directory, which may be on the classpath or filesystem. The - * directory should contain subdirectories, each of which contains a prompt template and a - * configuration file. The configuration file should be named "config.json" and the prompt - * template should be named "skprompt.txt". - * - * @param parentDirectory The parent directory containing the plugin directories. - * @param pluginDirectoryName The name of the plugin directory. - * @param functionName The name of the function to import. - * @param promptTemplateFactory The factory to use for creating prompt templates. - * @param clazz The class to use for loading resources. If null, the classloader - * will be used. - * @return The imported plugin. - */ - @Nullable - public static KernelPlugin importPluginFromResourcesDirectory( - String parentDirectory, - String pluginDirectoryName, - String functionName, - @Nullable PromptTemplateFactory promptTemplateFactory, - @Nullable Class clazz) { - - String template = getTemplatePrompt(parentDirectory, pluginDirectoryName, functionName, - clazz); - - PromptTemplateConfig promptTemplateConfig = getPromptTemplateConfig(parentDirectory, - pluginDirectoryName, functionName, clazz); - - if (promptTemplateConfig == null) { - LOGGER.warn( - SemanticKernelResources.getString("unable.to.load.prompt.template.config.for.in"), - functionName, - pluginDirectoryName); - return null; - } - KernelFunction function = getKernelFunction(functionName, promptTemplateFactory, - promptTemplateConfig, template); - - HashMap> plugins = new HashMap<>(); - - plugins.put(functionName, function); - - return new KernelPlugin( - pluginDirectoryName, - promptTemplateConfig.getDescription(), - plugins); - } - - private static String getTemplatePrompt( - String pluginDirectory, - String pluginName, - String functionName, - @Nullable Class clazz) { - String promptFileName = pluginDirectory + File.separator + pluginName + File.separator - + functionName - + File.separator + PROMPT_FILE; - - try { - return getFileContents(promptFileName, clazz); - } catch (IOException e) { - LOGGER.error(SemanticKernelResources.getString("failed.to.read.file1"), promptFileName, - e); - - throw new SKException("No plugins found in directory " + promptFileName); - } - } - - private static String getFileContents(String file, @Nullable Class clazz) - throws FileNotFoundException { - if (clazz == null) { - return EmbeddedResourceLoader.readFile(file, null, ResourceLocation.CLASSPATH_ROOT, - ResourceLocation.FILESYSTEM); - } - - return EmbeddedResourceLoader.readFile(file, clazz, ResourceLocation.CLASSPATH_ROOT, - ResourceLocation.CLASSPATH, ResourceLocation.FILESYSTEM); - } - - @Nullable - private static PromptTemplateConfig getPromptTemplateConfig( - String pluginDirectory, - String pluginName, String functionName, - @Nullable Class clazz) { - String configFileName = pluginDirectory + File.separator + pluginName + File.separator - + functionName - + File.separator + CONFIG_FILE; - - try { - String config = getFileContents(configFileName, clazz); - - return PromptTemplateConfig.parseFromJson(config); - } catch (Exception e) { - if (e instanceof SKException) { - LOGGER.error(SemanticKernelResources.getString("failed.to.parse.config.file"), - configFileName, e); - - throw new SKException("Failed to parse config file " + configFileName, e); - } else { - LOGGER.debug(SemanticKernelResources.getString("no.config.for.in"), functionName, - pluginName); - } - return null; - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/AggregatorPromptTemplateFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/AggregatorPromptTemplateFactory.java deleted file mode 100644 index 2c4bf5912..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/AggregatorPromptTemplateFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import java.util.ArrayList; -import java.util.List; -import reactor.util.annotation.NonNull; - -/** - * An collection of {@link PromptTemplateFactory} instances. The factory will try to create a - * {@link PromptTemplate} using each factory in the collection until one is successful. - */ -public class AggregatorPromptTemplateFactory implements PromptTemplateFactory { - - private final List templateFactories; - - /** - * Creates a new instance of {@link AggregatorPromptTemplateFactory}. - * - * @param templateFactories the factories to aggregate - */ - public AggregatorPromptTemplateFactory(List templateFactories) { - this.templateFactories = new ArrayList<>(templateFactories); - } - - @Override - public PromptTemplate tryCreate(@NonNull PromptTemplateConfig templateConfig) { - for (PromptTemplateFactory factory : templateFactories) { - try { - return factory.tryCreate(templateConfig); - } catch (UnknownTemplateFormatException ignored) { - // No-op - } - } - - throw new UnknownTemplateFormatException(templateConfig.getTemplateFormat()); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/HandlebarsPromptTemplateFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/HandlebarsPromptTemplateFactory.java deleted file mode 100644 index 2a9b991ff..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/HandlebarsPromptTemplateFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import java.util.Locale; - -import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate; - -import reactor.util.annotation.NonNull; - -/** - * A factory for creating a {@link HandlebarsPromptTemplate} instance for a - * {@code PromptTemplateConfig} that uses the handlebars template format. - */ -public class HandlebarsPromptTemplateFactory implements PromptTemplateFactory { - - /** - * The handlebars template format. - */ - public static final String HANDLEBARS_TEMPLATE_FORMAT = "handlebars"; - - /** - * Initializes a new instance of the {@link HandlebarsPromptTemplateFactory} class. - */ - public HandlebarsPromptTemplateFactory() { - } - - @Override - public PromptTemplate tryCreate(@NonNull PromptTemplateConfig templateConfig) { - if (templateConfig.getTemplateFormat() != null && - HANDLEBARS_TEMPLATE_FORMAT.equals( - templateConfig.getTemplateFormat().toLowerCase(Locale.ROOT))) { - return new HandlebarsPromptTemplate(templateConfig); - } - - throw new UnknownTemplateFormatException(templateConfig.getTemplateFormat()); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputConfig.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputConfig.java deleted file mode 100644 index 34e492e93..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Collections; -import java.util.List; - -/** - * Input configuration (list of all input parameters for a semantic function). - */ -public class InputConfig { - - private final List parameters; - - /** - * Creates a new instance of the {@link InputConfig} class. - * - * @param parameters the list of input parameters - */ - @JsonCreator - public InputConfig(@JsonProperty("parameters") List parameters) { - this.parameters = Collections.unmodifiableList(parameters); - } - - /** - * Gets the list of input parameters. - * - * @return the list of input parameters - */ - public List getParameters() { - return parameters; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputParameter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputParameter.java deleted file mode 100644 index 7dbb23694..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputParameter.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Input parameter for semantic functions - */ -public class InputParameter { - - private final String name; - private final String description; - private final String defaultValue; - - /** - * Creates a new instance of the {@link InputParameter} class. - * - * @param name name of the parameter - * @param description description of the parameter - * @param defaultValue default value of the parameter - */ - @JsonCreator - public InputParameter( - @JsonProperty("name") String name, - @JsonProperty("description") String description, - @JsonProperty("defaultValue") String defaultValue) { - this.name = name; - this.description = description; - this.defaultValue = defaultValue; - } - - /** - * Name of the parameter to pass to the function. e.g. when using "{{$input}}" the name is - * "input", when using "{{$style}}" the name is "style", etc. - * - * @return name - */ - public String getName() { - return name; - } - - /** - * Parameter description for UI apps and planner. Localization is not supported here. - * - * @return description - */ - public String getDescription() { - return description; - } - - /** - * Default value when nothing is provided - * - * @return the default value - */ - public String getDefaultValue() { - return defaultValue; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputVariable.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputVariable.java deleted file mode 100644 index 800422632..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/InputVariable.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.annotation.JsonAlias; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * Metadata for an input variable of a {@link KernelFunction}. - */ -public class InputVariable { - - private final String name; - @Nullable - private final String description; - @Nullable - private final String defaultValue; - private final boolean isRequired; - private final String type; - @Nullable - private final List enumValues; - - /** - * Creates a new instance of {@link InputVariable}. - * - * @param name the name of the input variable - * @param type the type of the input variable - * @param description the description of the input variable - * @param defaultValue the default value of the input variable - * @param isRequired whether the input variable is required - * @param enumValues the enum values of the input variable - */ - @JsonCreator - public InputVariable( - @JsonProperty("name") String name, - @JsonProperty("type") String type, - @JsonProperty("description") @Nullable String description, - @JsonProperty("default") @Nullable String defaultValue, - @JsonAlias({ "required", "is_required" }) @JsonProperty("is_required") boolean isRequired, - @JsonProperty("enum") @Nullable List enumValues) { - this.name = name; - this.description = description; - this.defaultValue = defaultValue; - this.isRequired = isRequired; - if (type == null) { - type = "java.lang.String"; - } - this.type = type; - if (enumValues != null) { - this.enumValues = Collections.unmodifiableList(enumValues); - } else { - this.enumValues = null; - } - } - - /** - * Creates a new instance of {@link InputVariable}. - * - * @param name the name of the input variable - */ - public InputVariable(String name) { - this.name = name; - this.type = String.class.getName(); - this.description = null; - this.defaultValue = null; - this.isRequired = true; - this.enumValues = null; - } - - /** - * Creates a new instance of {@link InputVariable}. - * - * @param name the name of the input variable - * @param type the type of the input variable - * @param description the description of the input variable - * @param defaultValue the default value of the input variable - * @param enumValues the enum values of the input variable - * @param required whether the input variable is required - * @return a new instance of {@link InputVariable} - */ - public static InputVariable build( - String name, - Class type, - @Nullable String description, - @Nullable String defaultValue, - @Nullable List enumValues, - boolean required) { - return new InputVariable(name, type.getName(), description, defaultValue, required, - enumValues); - } - - /** - * Gets the name of the input variable. - * - * @return the name of the input variable - */ - public String getName() { - return name; - } - - /** - * Gets the description of the input variable. - * - * @return the description of the input variable - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Gets the default value of the input variable. - * - * @return the default value of the input variable - */ - @Nullable - public String getDefaultValue() { - return defaultValue; - } - - /** - * Gets whether the input variable is required. - * - * @return whether the input variable is required - */ - public boolean isRequired() { - return isRequired; - } - - /** - * Gets the type of the input variable. - * - * @return the type of the input variable - */ - public String getType() { - return type; - } - - /** - * Gets the class of the type of the input variable. - * - * @return the class of the type of the input variable - */ - public Class getTypeClass() { - return KernelPluginFactory.getTypeForName(type); - } - - @Override - public int hashCode() { - return Objects.hash(name, type, description, defaultValue, isRequired); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (!getClass().isInstance(obj)) { - return false; - } - - InputVariable other = (InputVariable) obj; - if (!Objects.equals(name, other.name)) { - return false; - } - if (!Objects.equals(type, other.type)) { - return false; - } - if (!Objects.equals(description, other.description)) { - return false; - } - if (!Objects.equals(defaultValue, other.defaultValue)) { - return false; - } - return isRequired == other.isRequired; - } - - /** - * Gets the possible enum values of the input variable. - * - * @return the possible enum values of the input variable - */ - @Nullable - public List getEnumValues() { - return enumValues; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java deleted file mode 100644 index bf9e65658..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import reactor.util.annotation.NonNull; - -/** - * Arguments to a kernel function. - */ -public class KernelArguments implements Map> { - - /** - * Default key for the main input. - */ - public static final String MAIN_KEY = "input"; - - protected final CaseInsensitiveMap> variables; - protected final Map executionSettings; - - /** - * Create a new instance of KernelArguments. - * - * @param variables The variables to use for the function invocation. - */ - protected KernelArguments( - @Nullable Map> variables, - @Nullable Map executionSettings) { - if (variables == null) { - this.variables = new CaseInsensitiveMap<>(); - } else { - this.variables = new CaseInsensitiveMap<>(variables); - } - - if (executionSettings == null) { - this.executionSettings = new HashMap<>(); - } else { - this.executionSettings = new HashMap<>(executionSettings); - } - } - - /** - * Create a new instance of KernelArguments. - * - * @param content The content to use for the function invocation. - */ - protected KernelArguments(@NonNull ContextVariable content) { - this(); - this.variables.put(MAIN_KEY, content); - } - - /** - * Create a new instance of KernelArguments. - */ - protected KernelArguments() { - this.variables = new CaseInsensitiveMap<>(); - this.executionSettings = new HashMap<>(); - } - - /** - * Create a new instance of KernelArguments. - * - * @param arguments The arguments to copy. - */ - protected KernelArguments(@NonNull KernelArguments arguments) { - this.variables = new CaseInsensitiveMap<>(arguments.variables); - this.executionSettings = new HashMap<>(arguments.executionSettings); - } - - /** - * Get the prompt execution settings - * - * @return prompt execution settings - */ - @Nonnull - public Map getExecutionSettings() { - return Collections.unmodifiableMap(executionSettings); - } - - /** - * Get the input (entry in the MAIN_KEY slot) - * - * @return input - */ - @Nullable - public ContextVariable getInput() { - return get(MAIN_KEY); - } - - /** - * Create formatted string of the variables - * - * @return formatted string - */ - public String prettyPrint() { - return variables.entrySet().stream() - .reduce( - "", - (str, entry) -> str - + System.lineSeparator() - + entry.getKey() - + ": " - + entry.getValue().toPromptString(ContextVariableTypes.getGlobalTypes()), - (a, b) -> a + b); - } - - /** - * Return the variable with the given name - * - * @param key variable name - * @return content of the variable - */ - @Nullable - public ContextVariable get(String key) { - return variables.get(key); - } - - /** - * Return the variable with the given name - * - * @param key variable name - * @return content of the variable - */ - @Nullable - ContextVariable get(String key, Class clazz) { - ContextVariable value = variables.get(key); - if (value == null) { - return null; - } else if (clazz.isAssignableFrom(value.getType().getClazz())) { - return (ContextVariable) value; - } - - throw new SKException( - String.format( - "Variable %s is of type %s, but requested type is %s", - key, value.getType().getClazz(), clazz)); - } - - /** - * Return whether the variable with the given name is {@code null} or empty. - * - * @param key the key for the variable - * @return {@code true} if the variable is {@code null} or empty, {@code false} otherwise - */ - public boolean isNullOrEmpty(String key) { - return get(key) == null || get(key).isEmpty(); - } - - @Override - public int size() { - return variables.size(); - } - - @Override - public boolean isEmpty() { - return variables.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return variables.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return variables.containsValue(value); - } - - @Override - @Nullable - public ContextVariable get(Object key) { - return variables.get(key); - } - - @Override - public ContextVariable put(String key, ContextVariable value) { - return variables.put(key, value); - } - - @Override - public ContextVariable remove(Object key) { - return variables.remove(key); - } - - @Override - public void putAll(Map> m) { - variables.putAll(m); - } - - @Override - public void clear() { - variables.clear(); - } - - @Override - public Set keySet() { - return variables.keySet(); - } - - @Override - public Collection> values() { - return variables.values(); - } - - @Override - public Set>> entrySet() { - return variables.entrySet(); - } - - /** - * Create a copy of the current instance - * - * @return copy of the current instance - */ - public KernelArguments copy() { - return new KernelArguments(variables, executionSettings); - } - - /** - * Create a new instance of Builder. - * - * @return Builder - */ - public static Builder builder() { - return new Builder<>(KernelArguments::new); - } - - /** - * Builder for ContextVariables - */ - public static class Builder implements SemanticKernelBuilder { - - private final Function constructor; - private final Map> variables; - private final Map executionSettings; - - protected Builder(Function constructor) { - this.constructor = constructor; - this.variables = new HashMap<>(); - this.executionSettings = new HashMap<>(); - } - - /** - * Builds an instance with the given content in the default main key - * - * @param content Entry to place in the "input" slot - * @param Type of the value - * @return {$code this} Builder for fluent coding - */ - public Builder withInput(ContextVariable content) { - return withVariable(MAIN_KEY, content); - } - - /** - * Builds an instance with the given content in the default main key - * - * @param content Entry to place in the "input" slot - * @return {$code this} Builder for fluent coding - * @throws SKException if the content cannot be converted to a ContextVariable - */ - public Builder withInput(Object content) { - return withInput(ContextVariable.ofGlobalType(content)); - } - - /** - * Builds an instance with the given content in the default main key - * - * @param content Entry to place in the "input" slot - * @param typeConverter Type converter for the content - * @param Type of the value - * @return {$code this} Builder for fluent coding - * @throws SKException if the content cannot be converted to a ContextVariable - */ - public Builder withInput(T content, ContextVariableTypeConverter typeConverter) { - return withInput(new ContextVariable<>( - new ContextVariableType<>( - typeConverter, - typeConverter.getType()), - content)); - } - - /** - * Builds an instance with the given variables - * - * @param map Existing variables - * @return {$code this} Builder for fluent coding - */ - public Builder withVariables(@Nullable Map> map) { - if (map == null) { - return this; - } - variables.putAll(map); - return this; - } - - /** - * Set variable - * - * @param key variable name - * @param value variable value - * @param Type of the value - * @return {$code this} Builder for fluent coding - */ - public Builder withVariable(String key, ContextVariable value) { - variables.put(key, value); - return this; - } - - /** - * Set variable, uses the default type converters - * - * @param key variable name - * @param value variable value - * @return {$code this} Builder for fluent coding - * @throws SKException if the value cannot be converted to a ContextVariable - */ - public Builder withVariable(String key, Object value) { - if (value instanceof ContextVariable) { - return withVariable(key, (ContextVariable) value); - } - return withVariable(key, ContextVariable.ofGlobalType(value)); - } - - /** - * Set variable - * - * @param key variable name - * @param value variable value - * @param typeConverter Type converter for the value - * @param Type of the value - * @return {$code this} Builder for fluent coding - * @throws SKException if the value cannot be converted to a ContextVariable - */ - public Builder withVariable(String key, T value, - ContextVariableTypeConverter typeConverter) { - return withVariable(key, new ContextVariable<>( - new ContextVariableType<>( - typeConverter, - typeConverter.getType()), - value)); - } - - /** - * Set prompt execution settings - * - * @param executionSettings Execution settings - * @return {$code this} Builder for fluent coding - */ - public Builder withExecutionSettings(PromptExecutionSettings executionSettings) { - return withExecutionSettings(Collections.singletonList(executionSettings)); - } - - /** - * Set prompt execution settings - * - * @param executionSettings Execution settings - * @return {$code this} Builder for fluent coding - */ - public Builder withExecutionSettings( - Map executionSettings) { - if (executionSettings == null) { - return this; - } - - this.executionSettings.putAll(executionSettings); - return this; - } - - /** - * Set prompt execution settings - * - * @param executionSettings Execution settings - * @return {$code this} Builder for fluent coding - */ - public Builder withExecutionSettings(List executionSettings) { - if (executionSettings == null) { - return this; - } - - for (PromptExecutionSettings settings : executionSettings) { - String serviceId = settings.getServiceId(); - - if (this.executionSettings.containsKey(serviceId)) { - if (serviceId.equals(PromptExecutionSettings.DEFAULT_SERVICE_ID)) { - throw new SKException( - String.format( - "Multiple prompt execution settings with the default service id '%s' or no service id have been provided. Specify a single default prompt execution settings and provide a unique service id for all other instances.", - PromptExecutionSettings.DEFAULT_SERVICE_ID)); - } - - throw new SKException( - String.format( - "Multiple prompt execution settings with the service id '%s' have been provided. Specify a unique service id for all instances.", - serviceId)); - } - - this.executionSettings.put(serviceId, settings); - } - - return this; - } - - @Override - public U build() { - KernelArguments arguments = new KernelArguments(variables, executionSettings); - return constructor.apply(arguments); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java deleted file mode 100644 index 742e84572..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.implementation.Todo; -import com.microsoft.semantickernel.orchestration.FunctionInvocation; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -/** - * Semantic Kernel callable function interface. The Semantic Kernel creates {@code KernelFunction}s - * from prompts, templates, or plugin methods. - * - * @param The type of the result of the function - * @see com.microsoft.semantickernel.semanticfunctions - * @see com.microsoft.semantickernel.plugin - * @see com.microsoft.semantickernel.semanticfunctions.annotations - */ -public abstract class KernelFunction { - - private final KernelFunctionMetadata metadata; - - @Nullable - private final Map executionSettings; - - /** - * Create a new instance of KernelFunction. - * - * @param metadata The metadata for the function - * @param executionSettings The execution settings for the function - * @see com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt - * @see com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod - */ - protected KernelFunction( - KernelFunctionMetadata metadata, - @Nullable Map executionSettings) { - this.metadata = metadata; - this.executionSettings = new HashMap<>(); - if (executionSettings != null) { - this.executionSettings.putAll(executionSettings); - } - } - - /** - * Creates a {@link KernelFunction} instance for a method, specified via a {@link Method} - * instance - * - * @param The return type of the method. - * @param method The method to be represented via the created {@link KernelFunction}. - * @param target The target object for the {@code method} if it represents an instance method. - * This should be {@code null} if and only if {@code method} is a static method. - * @return The created {@link KernelFunction} wrapper for {@code method}. - */ - - public static KernelFunctionFromMethod.Builder createFromMethod( - Method method, - Object target) { - return KernelFunctionFromMethod.builder() - .withMethod(method) - .withTarget(target); - } - - /** - * Creates a {@link KernelFunction} instance based on a given prompt - * - * @param prompt The prompt to be used for the created {@link KernelFunction}. - * @param The return type of the method - * @return The builder for creating a {@link KernelFunction} instance. - */ - public static FromPromptBuilder createFromPrompt(String prompt) { - return KernelFunctionFromPrompt.builder() - .withTemplate(prompt); - } - - /** - * Builder for creating a {@link KernelFunction} instance for a given - * {@link PromptTemplateConfig}. - * - * @param promptTemplateConfiguration The configuration for the prompt template. - * @param The return type of the method - * @return The builder for creating a {@link KernelFunction} instance. - */ - public static FromPromptBuilder createFromPrompt( - PromptTemplateConfig promptTemplateConfiguration) { - return KernelFunctionFromPrompt.builder() - .withPromptTemplateConfig(promptTemplateConfiguration); - } - - /** - * Get the plugin name of the function. - * @return The name of the plugin that this function is within - */ - @Nullable - public String getPluginName() { - return metadata.getPluginName(); - } - - /** - * Get the name of the function. - * @return The name of this function - */ - public String getName() { - return metadata.getName(); - } - - /** - * Get the description of the function. - * @return A description of the function - */ - @Nullable - public String getDescription() { - return metadata.getDescription(); - } - - /** - * Create a string for generating an embedding for a function. - * - * @return A string for generating an embedding for a function. - */ - public String toEmbeddingString() { - throw new Todo(); - } - - /** - * Create a manual-friendly string for a function. - * - * @param includeOutputs Whether to include function outputs in the string. - * @return A manual-friendly string for a function. - */ - public String toManualString(boolean includeOutputs) { - throw new Todo(); - } - - /** - * Get an unmodifiable map of the execution settings for the function. - * - * @return An unmodifiable map of the execution settings for the function - */ - public Map getExecutionSettings() { - return Collections.unmodifiableMap(executionSettings); - } - - /** - * Get the metadata for the function. - * - * @return The metadata for the function - */ - public KernelFunctionMetadata getMetadata() { - return metadata; - } - - /** - * Invokes this KernelFunction. - *

- * If the {@code variableType} parameter is provided, the {@link ContextVariableType} is used to - * convert the result of the function to the appropriate {@link FunctionResult}. The - * {@code variableType} is not required for converting well-known types such as {@link String} - * and {@link Integer} which have pre-defined {@code ContextVariableType}s. - *

- * The {@link InvocationContext} allows for customization of the behavior of function, including - * the ability to pass in {@link KernelHooks} {@link PromptExecutionSettings}, and - * {@link ToolCallBehavior}. - *

- * The difference between calling the {@code KernelFunction.invokeAsync} method directly and - * calling the {@code Kernel.invokeAsync} method is that the latter adds the global KernelHooks - * (if any) to the {@link InvocationContext}. Calling {@code KernelFunction.invokeAsync} - * directly does not add the global hooks. - * - * @param kernel The Kernel containing services, plugins, and other state for use - * throughout the operation. - * @param arguments The arguments to pass to the function's invocation - * @param variableType The type of the {@link ContextVariable} returned in the - * {@link FunctionResult} - * @param invocationContext The arguments to pass to the function's invocation - * @return The result of the function's execution. - * @see FunctionResult#getResultVariable() - */ - public abstract Mono> invokeAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext); - - /** - * Invokes this KernelFunction. - *

- * If the {@code variableType} parameter is provided, the {@link ContextVariableType} is used to - * convert the result of the function to the appropriate {@link FunctionResult}. The - * {@code variableType} is not required for converting well-known types such as {@link String} - * and {@link Integer} which have pre-defined {@code ContextVariableType}s. - *

- * The {@link InvocationContext} allows for customization of the behavior of function, including - * the ability to pass in {@link KernelHooks} {@link PromptExecutionSettings}, and - * {@link ToolCallBehavior}. - *

- * The difference between calling the {@code KernelFunction.invokeAsync} method directly and - * calling the {@code Kernel.invokeAsync} method is that the latter adds the global KernelHooks - * (if any) to the {@link InvocationContext}. Calling {@code KernelFunction.invokeAsync} - * directly does not add the global hooks. - * - * @param kernel The Kernel containing services, plugins, and other state for use - * throughout the operation. - * @param arguments The arguments to pass to the function's invocation - * @param variableType The type of the {@link ContextVariable} returned in the - * {@link FunctionResult} - * @param invocationContext The arguments to pass to the function's invocation - * @return The result of the function's execution. - * @see FunctionResult#getResultVariable() - */ - public FunctionResult invoke( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext) { - return invokeAsync(kernel, arguments, variableType, invocationContext).block(); - } - - /** - * Invokes this KernelFunction. - * - * @param kernel The Kernel containing services, plugins, and other state for use throughout the - * operation. - * @return The result of the function's execution. - */ - public FunctionInvocation invokeAsync(Kernel kernel) { - return new FunctionInvocation<>(kernel, this); - } - - /** - * Invokes this KernelFunction. - * - * @param kernel The Kernel containing services, plugins, and other state for use throughout the - * operation. - * @return The result of the function's execution. - */ - public FunctionResult invoke(Kernel kernel) { - return invokeAsync(kernel).block(); - } - - /** - * Builder for creating a {@link KernelFunction} from a prompt. - * - * @param The type of the result of the function - * @see com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt.Builder - */ - public interface FromPromptBuilder { - - /** - * Set the name of the function. - * - * @param name The name of the function - * @return The builder - */ - FromPromptBuilder withName(@Nullable String name); - - /** - * Set the input parameters for the function. - * - * @param inputVariables The input parameters for the function - * @return The builder - */ - FromPromptBuilder withInputParameters( - @Nullable List inputVariables); - - /** - * Set the prompt template for the function. - * - * @param promptTemplate The prompt template for the function - * @return The builder - */ - FromPromptBuilder withPromptTemplate( - @Nullable PromptTemplate promptTemplate); - - /** - * Set the execution settings for the function. - * - * @param executionSettings The execution settings for the function - * @return The builder - */ - FromPromptBuilder withExecutionSettings( - @Nullable Map executionSettings); - - /** - * Set the default execution settings for the function. - * - * @param executionSettings The default execution settings for the function - * @return The builder - */ - FromPromptBuilder withDefaultExecutionSettings( - @Nullable PromptExecutionSettings executionSettings); - - /** - * Set the description of the function. - * - * @param description The description of the function - * @return The builder - */ - FromPromptBuilder withDescription(@Nullable String description); - - /** - * Set the template for the function. - * - * @param template The template for the function - * @return The builder - */ - FromPromptBuilder withTemplate(@Nullable String template); - - /** - * Create a new KernelFunction instance from the builder. - * - * @return The new KernelFunction instance - */ - KernelFunction build(); - - /** - * Set the template format for the function. - * - * @param templateFormat The template format for the function - * @return The builder - */ - FromPromptBuilder withTemplateFormat(String templateFormat); - - /** - * Set the output variable for the function. - * - * @param outputVariable The output variable for the function - * @param The type of the output variable - * @return The builder - */ - FromPromptBuilder withOutputVariable( - @Nullable OutputVariable outputVariable); - - /** - * Set the output variable for the function. - * - * @param description The description of the output variable - * @param type The type of the output variable - * @return The builder - */ - FromPromptBuilder withOutputVariable(@Nullable String description, String type); - - /** - * Set the prompt template factory used to build the function. - * - * @param promptTemplateFactory The prompt template factory for the function - * @return The builder - */ - FromPromptBuilder withPromptTemplateFactory( - @Nullable PromptTemplateFactory promptTemplateFactory); - - /** - * Set the prompt template config used to build the function. - * - * @param promptTemplateConfig The prompt template config for the function - * @return The builder - */ - FromPromptBuilder withPromptTemplateConfig( - @Nullable PromptTemplateConfig promptTemplateConfig); - - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java deleted file mode 100644 index 76936cf23..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.exceptions.SKException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nullable; -import reactor.util.annotation.NonNull; - -/** - * Arguments to a kernel function. - * - * @deprecated Use {@link KernelArguments} instead. - */ -@Deprecated -public class KernelFunctionArguments extends KernelArguments { - - /** - * Default key for the main input. - */ - public static final String MAIN_KEY = "input"; - - /** - * Create a new instance of KernelFunctionArguments. - * - * @param variables The variables to use for the function invocation. - */ - protected KernelFunctionArguments( - @Nullable Map> variables) { - super(variables, null); - } - - /** - * Create a new instance of KernelFunctionArguments. - * - * @param content The content to use for the function invocation. - */ - protected KernelFunctionArguments(@NonNull ContextVariable content) { - super(content); - } - - /** - * Create a new instance of KernelArguments. - * - * @param arguments The arguments to copy. - */ - protected KernelFunctionArguments(@NonNull KernelArguments arguments) { - super(arguments); - } - - /** - * Create a new instance of KernelFunctionArguments. - */ - protected KernelFunctionArguments() { - super(); - } - - /** - * Create a new instance of Builder. - * - * @return Builder - */ - public static Builder builder() { - return new KernelFunctionArguments.Builder(); - } - - /** - * Get the input (entry in the MAIN_KEY slot) - * - * @return input - */ - @Nullable - public ContextVariable getInput() { - return get(MAIN_KEY); - } - - /** - * Create formatted string of the variables - * - * @return formatted string - */ - public String prettyPrint() { - return variables.entrySet().stream() - .reduce( - "", - (str, entry) -> str - + System.lineSeparator() - + entry.getKey() - + ": " - + entry.getValue().toPromptString(ContextVariableTypes.getGlobalTypes()), - (a, b) -> a + b); - } - - /** - * Return the variable with the given name - * - * @param key variable name - * @return content of the variable - */ - @Nullable - public ContextVariable get(String key) { - return variables.get(key); - } - - /** - * Return the variable with the given name - * - * @param key variable name - * @return content of the variable - */ - @Nullable - ContextVariable get(String key, Class clazz) { - ContextVariable value = variables.get(key); - if (value == null) { - return null; - } else if (clazz.isAssignableFrom(value.getType().getClazz())) { - return (ContextVariable) value; - } - - throw new SKException( - String.format( - "Variable %s is of type %s, but requested type is %s", - key, value.getType().getClazz(), clazz)); - } - - /** - * Return whether the variable with the given name is {@code null} or empty. - * - * @param key the key for the variable - * @return {@code true} if the variable is {@code null} or empty, {@code false} otherwise - */ - public boolean isNullOrEmpty(String key) { - return get(key) == null || get(key).isEmpty(); - } - - @Override - public int size() { - return variables.size(); - } - - @Override - public boolean isEmpty() { - return variables.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return variables.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return variables.containsValue(value); - } - - @Override - @Nullable - public ContextVariable get(Object key) { - return variables.get(key); - } - - @Override - public ContextVariable put(String key, ContextVariable value) { - return variables.put(key, value); - } - - @Override - public ContextVariable remove(Object key) { - return variables.remove(key); - } - - @Override - public void putAll(Map> m) { - variables.putAll(m); - } - - @Override - public void clear() { - variables.clear(); - } - - @Override - public Set keySet() { - return variables.keySet(); - } - - @Override - public Collection> values() { - return variables.values(); - } - - @Override - public Set>> entrySet() { - return variables.entrySet(); - } - - /** - * Create a copy of the current instance - * - * @return copy of the current instance - */ - public KernelFunctionArguments copy() { - return new KernelFunctionArguments(variables); - } - - /** - * Builder for ContextVariables - * - * @deprecated Use {@link KernelArguments} builder instead. - */ - @Deprecated - public static class Builder extends KernelArguments.Builder { - - /** - * Create a new instance of Builder. - */ - @Deprecated - public Builder() { - super(KernelFunctionArguments::new); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethod.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethod.java deleted file mode 100644 index 6704255ff..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethod.java +++ /dev/null @@ -1,926 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter.NO_DEFAULT_VALUE; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter.NoopConverter; -import com.microsoft.semantickernel.exceptions.AIException; -import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.hooks.FunctionInvokedEvent; -import com.microsoft.semantickernel.hooks.FunctionInvokingEvent; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.implementation.telemetry.FunctionSpan; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - -/** - * A {@link KernelFunction} that is created from a method. This class is used to create a - * {@link KernelFunction} from a method that is annotated with {@link DefineKernelFunction} and - * {@link KernelFunctionParameter}. - * - * @param the return type of the function - */ -public class KernelFunctionFromMethod extends KernelFunction { - - private final static Logger LOGGER = LoggerFactory.getLogger(KernelFunctionFromMethod.class); - - private final ImplementationFunc function; - - private KernelFunctionFromMethod( - ImplementationFunc implementationFunc, - @Nullable String pluginName, - String functionName, - @Nullable String description, - @Nullable List parameters, - OutputVariable returnParameter) { - super( - new KernelFunctionMetadata<>( - pluginName, - functionName, - description, - parameters, - returnParameter), - null); - this.function = implementationFunc; - } - - /** - * Creates a new instance of {@link KernelFunctionFromMethod} from a method. - * - * @param method the method to create the function from - * @param target the instance of the class that the method is a member of - * @param pluginName the name of the plugin which the function belongs to - * @param functionName the name of the function - * @param description the description of the function - * @param parameters the parameters of the function - * @param returnParameter the return parameter of the function - * @param the return type of the function - * @return a new instance of {@link KernelFunctionFromMethod} - */ - @SuppressWarnings("unchecked") - public static KernelFunction create( - Method method, - Object target, - @Nullable String pluginName, - @Nullable String functionName, - @Nullable String description, - @Nullable List parameters, - @Nullable OutputVariable returnParameter) { - - MethodDetails methodDetails = getMethodDetails(functionName, method, target); - - if (description == null || description.isEmpty()) { - description = methodDetails.getDescription(); - } - - if (parameters == null || parameters.isEmpty()) { - parameters = methodDetails.getParameters(); - } - - if (returnParameter == null) { - returnParameter = methodDetails.getReturnParameter(); - } - - // unchecked cast - return (KernelFunction) new KernelFunctionFromMethod<>( - methodDetails.getFunction(), - pluginName, - methodDetails.getName(), - description, - parameters, - returnParameter); - } - - private static MethodDetails getMethodDetails( - @Nullable String functionName, - Method method, - Object target) { - - DefineKernelFunction annotation = method.getAnnotation(DefineKernelFunction.class); - - String description = null; - String returnDescription = null; - if (annotation != null) { - if (!annotation.description().isEmpty()) { - description = annotation.description(); - } - if (!annotation.returnDescription().isEmpty()) { - returnDescription = annotation.returnDescription(); - } - } - - if (functionName == null || functionName.isEmpty()) { - functionName = method.getName(); - } - - return new MethodDetails( - functionName, - description, - getFunction(method, target), - getParameters(method), - new OutputVariable<>( - returnDescription, - method.getReturnType())); - } - - /** - * Gets the function from the method. - * - * @param method the method to invoke - * @param instance the instance to invoke the method on - * @param the return type of the function - * @return the function representing the method - */ - @SuppressWarnings("unchecked") - public static ImplementationFunc getFunction(Method method, Object instance) { - return (kernel, function, arguments, variableType, invocationContext) -> { - InvocationContext context; - if (invocationContext == null) { - context = InvocationContext.builder().build(); - } else { - context = invocationContext; - } - - // kernelHooks must be effectively final for lambda - KernelHooks kernelHooks = KernelHooks.merge( - kernel.getGlobalKernelHooks(), - context.getKernelHooks()); - - FunctionInvokingEvent updatedState = kernelHooks - .executeHooks( - new FunctionInvokingEvent(function, arguments)); - KernelArguments updatedArguments = updatedState != null - ? updatedState.getArguments() - : arguments; - - try { - List args = Arrays.stream(method.getParameters()) - .map(getParameters(method, updatedArguments, kernel, context)) - .collect(Collectors.toList()); - - Mono mono; - try { - if (method.getReturnType().isAssignableFrom(Mono.class)) { - mono = (Mono) method.invoke(instance, args.toArray()); - } else { - mono = invokeAsyncFunction(method, instance, args); - } - } catch (Exception e) { - return Mono.error( - new SKException("Function threw an exception: " + method.getName(), e)); - } - - return mono - .flatMap(it -> { - try { - return Mono.just((T) it); - } catch (ClassCastException e) { - return Mono.error( - new SKException("Return type does not match the expected type", e)); - } - }) - .map(it -> { - // If given a variable type, use it. - // If it's wrong, then it's a programming error on the part of the caller. - if (variableType != null) { - if (!variableType.getClazz().isAssignableFrom(it.getClass())) { - throw new SKException(String.format( - "Return parameter type from %s.%s does not match the expected type %s", - function.getPluginName(), function.getName(), - it.getClass().getName())); - } - return new FunctionResult<>( - new ContextVariable<>(variableType, it), it); - } - - Class returnParameterType = function - .getMetadata() - .getOutputVariableType() - .getType(); - - // If the function has a return type that has a ContextVariableType, use it. - ContextVariableType contextVariableType = getContextVariableType( - context, - returnParameterType); - if (contextVariableType == null) { - // If getting the context variable type from the function fails, default to - // using the NoopConverter. - contextVariableType = getDefaultContextVariableType( - returnParameterType); - } - - if (contextVariableType != null) { - return new FunctionResult<>( - new ContextVariable<>(contextVariableType, it), - it); - } - - // If we get here, then either the returnParameterType doesn't match T - throw new SKException(String.format( - "Return parameter type from %s.%s does not match the expected type %s", - function.getPluginName(), function.getName(), it.getClass().getName())); - - }) - .map(it -> { - FunctionInvokedEvent updatedResult = kernelHooks - .executeHooks( - new FunctionInvokedEvent<>( - function, - updatedArguments, - it)); - return updatedResult.getResult(); - }); - } catch (Exception e) { - return Mono.error(e); - } - }; - } - - @Nullable - @SuppressWarnings("unchecked") - private static ContextVariableType getContextVariableType( - InvocationContext invocationContext, Class clazz) { - - if (clazz != null) { - try { - // unchecked cast - Class tClazz = (Class) clazz; - ContextVariableType type = invocationContext.getContextVariableTypes() - .getVariableTypeForClass(tClazz); - return type; - } catch (ClassCastException | SKException e) { - // SKException is thrown from ContextVariableTypes.getDefaultVariableTypeForClass - // if there is no default variable type for the class. - // Fallthrough. Let the caller handle a null return. - } - } - return null; - } - - @Nullable - @SuppressWarnings("unchecked") - private static ContextVariableType getDefaultContextVariableType(Class clazz) { - - if (clazz != null) { - try { - // unchecked cast - Class tClazz = (Class) clazz; - ContextVariableTypeConverter noopConverter = new NoopConverter<>(tClazz); - - return new ContextVariableType<>(noopConverter, tClazz); - - } catch (ClassCastException e) { - // Fallthrough. Let the caller handle a null return. - } - } - return null; - } - - private static Mono invokeAsyncFunction( - Method method, Object instance, List args) { - return Mono.defer( - () -> Mono.fromCallable( - () -> { - try { - if (method.getReturnType().equals(void.class) - || method.getReturnType() - .equals(Void.class)) { - method.invoke(instance, args.toArray()); - return null; - } else { - return method.invoke(instance, args.toArray()); - } - } catch (InvocationTargetException e) { - throw new AIException( - ErrorCodes.INVALID_REQUEST, - "Function threw an exception: " - + method.getName(), - e.getCause()); - } catch (IllegalAccessException e) { - throw new AIException( - ErrorCodes.INVALID_REQUEST, - "Unable to access function " - + method.getName(), - e); - } - }) - .flatMap(it -> { - if (it == null) { - return Mono.empty(); - } else { - return Mono.just(it); - } - }) - .subscribeOn(Schedulers.boundedElastic())); - } - - @Nullable - private static Function getParameters( - Method method, - @Nullable KernelArguments context, - Kernel kernel, - InvocationContext invocationContext) { - return parameter -> { - if (KernelArguments.class.isAssignableFrom(parameter.getType())) { - return context; - } else if (Kernel.class.isAssignableFrom(parameter.getType())) { - return kernel; - } else { - return getArgumentValue(method, context, parameter, kernel, invocationContext); - } - }; - } - - @Nullable - private static Object getArgumentValue( - Method method, - @Nullable KernelArguments context, - Parameter parameter, - Kernel kernel, - InvocationContext invocationContext) { - // The actual type of the method argument - Class targetArgType = parameter.getType(); - - if (Kernel.class.isAssignableFrom(targetArgType)) { - return kernel; - } else if (SemanticKernelTelemetry.class.isAssignableFrom(targetArgType)) { - return invocationContext.getTelemetry(); - } - - String variableName = getGetVariableName(parameter); - ContextVariable variable = getVariableFromContext(method, context, variableName); - - // The Value of what has been provided - Object sourceValue = null; - ContextVariableType sourceType = null; - - // if needed extract the default value from annotation and substitute it for the missing variable - variable = extractDefaultTypeFromAnnotation( - method, - parameter, - invocationContext, - variable, - sourceValue, - variableName); - - if (variable != null) { - sourceValue = variable.getValue(); - sourceType = variable.getType(); - } - - Class requestedType = targetArgType; - - KernelFunctionParameter annotation = parameter.getAnnotation(KernelFunctionParameter.class); - if (annotation != null && annotation.type() != null) { - requestedType = annotation.type(); - } - - // Ignore string as there is a good chance the developer user left it to default - if (requestedType != String.class && !targetArgType.isAssignableFrom(requestedType)) { - throw new AIException( - AIException.ErrorCodes.INVALID_CONFIGURATION, - "Annotation on method: " + method.getName() + " requested conversion to type: " - + requestedType.getName() - + ", however this cannot be assigned to parameter of type: " - + targetArgType); - } - - if (requestedType == String.class && !targetArgType.isAssignableFrom(requestedType)) { - LOGGER.warn( - SemanticKernelResources.getString("annotation.on.method.is.requesting.a.string"), - method.getName(), - targetArgType.getName()); - } - - // First try to convert to the type requested from the annotation - Object converted = toObjectType( - parameter.getName(), - sourceType, - sourceValue, - requestedType, - invocationContext); - - if (targetArgType.isInstance(converted)) { - return converted; - } - - if (converted != null) { - // Could not convert to requested type, try to target type - ContextVariable convertedCv = invocationContext - .getContextVariableTypes() - .contextVariableOf(converted); - - converted = toObjectType( - parameter.getName(), - convertedCv.getType(), - convertedCv, - targetArgType, - invocationContext); - } - - if (targetArgType.isInstance(converted)) { - return converted; - } - - // Could not convert to requested type, try to target type - return toObjectType( - parameter.getName(), - sourceType, - sourceValue, - targetArgType, - invocationContext); - } - - @Nullable - private static Object toObjectType( - String parameterName, - - @Nullable ContextVariableType sourceType, - @Nullable Object sourceValue, - - Class targetArgType, - InvocationContext invocationContext) { - - if (sourceType != null) { - - if (targetArgType.isAssignableFrom(sourceType.getClazz())) { - return sourceValue; - } - - if (isPrimitive(sourceType.getClazz(), targetArgType)) { - return sourceValue; - } - - ContextVariableTypeConverter c = sourceType.getConverter(); - - Object converted = c.toObject(invocationContext.getContextVariableTypes(), sourceValue, - targetArgType, false); - if (converted != null) { - return converted; - } - } - - // Well-known types only - ContextVariableType converter = invocationContext.getContextVariableTypes() - .getVariableTypeForClass(targetArgType); - if (converter != null) { - try { - Object converted = converter.getConverter().fromObject(sourceValue); - if (converted != null) { - return converted; - } - } catch (NumberFormatException nfe) { - throw new AIException( - ErrorCodes.INVALID_CONFIGURATION, - "Invalid value for " - + parameterName - + " expected " - + targetArgType.getSimpleName() - + " but got " - + sourceValue); - } - } - - // If doing a type conversion fails, and we are going to a string, try using toPromptString - if (sourceType != null && targetArgType.equals(String.class)) { - ContextVariableTypeConverter c = sourceType.getConverter(); - - Object converted = c.toPromptString(invocationContext.getContextVariableTypes(), - sourceValue); - if (converted != null) { - return converted; - } - } - - return null; - } - - @Nullable - private static ContextVariable getVariableFromContext( - Method method, - @Nullable KernelArguments context, - String variableName) { - ContextVariable variable = context == null ? null : context.get(variableName); - - // If there is 1 argument use "input" or the only argument - if (variable == null && method.getParameters().length == 1) { - if (context != null) { - if (context.containsKey(KernelArguments.MAIN_KEY)) { - variable = context.get(KernelArguments.MAIN_KEY); - } else if (context.size() == 1) { - variable = context.values().iterator().next(); - } - } - } - return variable; - } - - @Nullable - private static ContextVariable extractDefaultTypeFromAnnotation( - Method method, - Parameter parameter, - InvocationContext invocationContext, - @Nullable ContextVariable variable, - @Nullable Object sourceValue, - String variableName) { - if (variable == null) { - KernelFunctionParameter annotation = parameter - .getAnnotation(KernelFunctionParameter.class); - if (annotation != null) { - // Convert from the defaultValue, which is a String to the argument type - // Expectation here is that the fromPromptString method will be able to handle a null or empty string - Class type = annotation.type(); - - ContextVariableType cvType = invocationContext - .getContextVariableTypes() - .getVariableTypeForClass(type); - - if (cvType != null) { - String defaultValue = annotation.defaultValue(); - Object value = cvType.getConverter().fromPromptString(defaultValue); - - variable = ContextVariable.convert(value, type, - invocationContext.getContextVariableTypes()); - } - - if (variable != null && NO_DEFAULT_VALUE.equals(sourceValue)) { - if (!annotation.required()) { - return null; - } - - throw new AIException( - ErrorCodes.INVALID_CONFIGURATION, - "Attempted to invoke function " - + method.getDeclaringClass().getName() - + "." - + method.getName() - + ". The context variable \"" - + variableName - + "\" has not been set, and no default value is" - + " specified."); - } - } - } - - if (variable == null && variableName.matches("arg\\d")) { - LOGGER.warn(formErrorMessage(method, parameter)); - } - - if (variable != null && NO_DEFAULT_VALUE.equals(sourceValue)) { - if (parameter.getName().matches("arg\\d")) { - throw new AIException( - AIException.ErrorCodes.INVALID_CONFIGURATION, - formErrorMessage(method, parameter)); - } else { - throw new AIException( - AIException.ErrorCodes.INVALID_CONFIGURATION, - "Unknown variable " + parameter.getName()); - } - } - - return variable; - } - - @SuppressWarnings("OperatorPrecedence") - private static boolean isPrimitive(Class argType, Class param) { - return (argType == Byte.class || argType == byte.class) && (param == Byte.class - || param == byte.class) || - (argType == Integer.class || argType == int.class) && (param == Integer.class - || param == int.class) - || - (argType == Long.class || argType == long.class) && (param == Long.class - || param == long.class) - || - (argType == Double.class || argType == double.class) && (param == Double.class - || param == double.class) - || - (argType == Float.class || argType == float.class) && (param == Float.class - || param == float.class) - || - (argType == Short.class || argType == short.class) && (param == Short.class - || param == short.class) - || - (argType == Boolean.class || argType == boolean.class) && (param == Boolean.class - || param == boolean.class) - || - (argType == Character.class || argType == char.class) && (param == Character.class - || param == char.class); - } - - private static String getGetVariableName(Parameter parameter) { - KernelFunctionParameter annotation = parameter.getAnnotation(KernelFunctionParameter.class); - - if (annotation == null || annotation.name() == null || annotation.name().isEmpty()) { - return parameter.getName(); - } - return annotation.name(); - } - - private static String formErrorMessage(Method method, Parameter parameter) { - Matcher matcher = Pattern.compile("arg(\\d)").matcher(parameter.getName()); - matcher.find(); - return MessageFormat.format( - SemanticKernelResources.getString( - "for.the.function.0.1.the.unknown.parameter.name.was.detected"), - method.getDeclaringClass().getName(), method.getName(), parameter.getName(), - matcher.group(1)); - } - - private static List getParameters(Method method) { - return Arrays.stream(method - .getParameters()) - .map(KernelFunctionFromMethod::toKernelParameterMetadata) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - @Nullable - private static InputVariable toKernelParameterMetadata(Parameter parameter) { - KernelFunctionParameter annotation = parameter.getAnnotation( - KernelFunctionParameter.class); - - String name = parameter.getName(); - String description = null; - String defaultValue = null; - boolean isRequired = true; - Class type = parameter.getType(); - - if (Kernel.class.isAssignableFrom(type) || KernelArguments.class.isAssignableFrom( - type)) { - return null; - } - if (annotation != null) { - name = annotation.name(); - description = annotation.description(); - defaultValue = annotation.defaultValue(); - isRequired = annotation.required(); - type = annotation.type(); - } - - List enumValues = getEnumOptions(type); - - return InputVariable.build( - name, - type, - description, - defaultValue, - enumValues, - isRequired); - } - - /** - * Gets the constants from an enum type. - * - * @param type the type to get the enum constants from - * @return a list of the enum constants or {@code null} if the type is not an enum - */ - public static @Nullable List getEnumOptions(Class type) { - List enumValues = null; - if (type.isEnum()) { - enumValues = Arrays.stream(type.getEnumConstants()) - .map(it -> { - return it.toString(); - }) - .collect(Collectors.toList()); - } - return enumValues; - } - - /** - * A builder for {@link KernelFunction}. - * - * @param the return type of the function - * @return a new instance of {@link Builder} - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Concrete implementation of the abstract method in KernelFunction. {@inheritDoc} - */ - @Override - public Mono> invokeAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext) { - - return Mono.deferContextual(contextView -> { - FunctionSpan span = FunctionSpan.build( - SemanticKernelTelemetry.getTelemetry(invocationContext), - contextView, - this.getPluginName(), - this.getName(), - arguments); - - return function - .invokeAsync(kernel, this, arguments, variableType, invocationContext) - .contextWrite(span.getReactorContextModifier()) - .doOnSuccess(span::onFunctionSuccess) - .doOnError(span::onFunctionError) - .doOnTerminate(span::close); - }); - } - - /** - * Concrete implementation of the abstract method in KernelFunction. - * - * @param the return type of the function - */ - public interface ImplementationFunc { - - /** - * Invokes the function. - * - * @param kernel the kernel to invoke the function on - * @param function the function to invoke - * @param arguments the arguments to the function - * @param variableType the variable type of the function - * @param invocationContext the invocation context - * @return a {@link Mono} that emits the result of the function invocation - */ - Mono> invokeAsync( - Kernel kernel, - KernelFunction function, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext); - - /** - * Invokes the function. - * - * @param kernel the kernel to invoke the function on - * @param function the function to invoke - * @param arguments the arguments to the function - * @param variableType the variable type of the function - * @param invocationContext the invocation context - * @return a {@link Mono} that emits the result of the function invocation - */ - default FunctionResult invoke( - Kernel kernel, - KernelFunction function, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext) { - return invokeAsync(kernel, function, arguments, variableType, - invocationContext).block(); - } - } - - /** - * A builder for {@link KernelFunction}. - * - * @param the return type of the function - */ - public static class Builder { - - @Nullable - private Method method; - @Nullable - private Object target; - @Nullable - private String pluginName; - @Nullable - private String functionName; - @Nullable - private String description; - @Nullable - private List parameters; - @Nullable - private OutputVariable returnParameter; - - /** - * Sets the method to use to build the function. - * - * @param method the method to use - * @return this instance of the {@link Builder} class - */ - @SuppressFBWarnings("EI_EXPOSE_REP2") - public Builder withMethod(Method method) { - this.method = method; - return this; - } - - /** - * Sets the target to use to build the function. - * - * @param target the target to use - * @return this instance of the {@link Builder} class - */ - public Builder withTarget(Object target) { - this.target = target; - return this; - } - - /** - * Sets the plugin name to use to build the function. - * - * @param pluginName the plugin name to use - * @return this instance of the {@link Builder} class - */ - public Builder withPluginName(String pluginName) { - this.pluginName = pluginName; - return this; - } - - /** - * Sets the function name to use to build the function. - * - * @param functionName the function name to use - * @return this instance of the {@link Builder} class - */ - public Builder withFunctionName(String functionName) { - this.functionName = functionName; - return this; - } - - /** - * Sets the description to use to build the function. - * - * @param description the description to use - * @return this instance of the {@link Builder} class - */ - public Builder withDescription(String description) { - this.description = description; - return this; - } - - /** - * Sets the parameters to use to build the function. - * - * @param parameters the parameters to use - * @return this instance of the {@link Builder} class - */ - public Builder withParameters(List parameters) { - this.parameters = new ArrayList<>(parameters); - return this; - } - - /** - * Sets the return parameter to use to build the function. - * - * @param returnParameter the return parameter to use - * @return this instance of the {@link Builder} class - */ - public Builder withReturnParameter(OutputVariable returnParameter) { - this.returnParameter = returnParameter; - return this; - } - - /** - * Builds a new instance of {@link KernelFunction}. - * - * @return a new instance of {@link KernelFunction} - */ - public KernelFunction build() { - - if (method == null) { - throw new SKException( - "To build a KernelFunctionFromMethod, a method must be provided"); - } - - if (target == null) { - throw new SKException( - "To build a plugin object must be provided"); - } - - return KernelFunctionFromMethod.create( - method, - target, - pluginName, - functionName, - description, - parameters, - returnParameter); - } - - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java deleted file mode 100644 index 642b5addc..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.azure.core.exception.HttpResponseException; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.hooks.FunctionInvokedEvent; -import com.microsoft.semantickernel.hooks.FunctionInvokingEvent; -import com.microsoft.semantickernel.hooks.KernelHooks; -import com.microsoft.semantickernel.hooks.PromptRenderedEvent; -import com.microsoft.semantickernel.hooks.PromptRenderingEvent; -import com.microsoft.semantickernel.implementation.telemetry.FunctionSpan; -import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.services.AIServiceSelection; -import com.microsoft.semantickernel.services.TextAIService; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * A {@link KernelFunction} implementation that is created from a prompt template. - * - * @param the type of the return value of the function - */ -public class KernelFunctionFromPrompt extends KernelFunction { - - private static final Logger LOGGER = LoggerFactory.getLogger(KernelFunctionFromPrompt.class); - - private final PromptTemplate template; - - /** - * Creates a new instance of {@link KernelFunctionFromPrompt}. - * - * @param template the prompt template to use for the function - * @param promptConfig the configuration for the prompt - * @param executionSettings the execution settings to use when invoking the function - */ - protected KernelFunctionFromPrompt( - PromptTemplate template, - PromptTemplateConfig promptConfig, - @Nullable Map executionSettings) { - super( - new KernelFunctionMetadata<>( - null, - getName(promptConfig), - promptConfig.getDescription(), - promptConfig.getKernelParametersMetadata(), - promptConfig.getKernelReturnParameterMetadata()), - executionSettings != null ? executionSettings : promptConfig.getExecutionSettings()); - this.template = template; - } - - private static String getName(PromptTemplateConfig promptConfig) { - if (promptConfig.getName() == null) { - return UUID.randomUUID().toString(); - } else { - return promptConfig.getName(); - } - } - - /** - * Creates a new instance of {@link Builder}. - * - * @param The type of the return value of the function - * @return a new instance of {@link Builder} - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Creates a new instance of {@link Builder}. - * - * @param returnType The type of the return value of the function - * @param The type of the return value of the function - * @return a new instance of {@link Builder} - */ - public static Builder builder(Class returnType) { - return new Builder<>(); - } - - private Flux> invokeInternalAsync( - Kernel kernel, - @Nullable KernelArguments argumentsIn, - @Nullable ContextVariableType contextVariableType, - @Nullable InvocationContext invocationContext) { - - InvocationContext context = invocationContext != null ? invocationContext - : InvocationContext.builder().build(); - - // must be effectively final for lambda - KernelHooks kernelHooks = KernelHooks.merge( - kernel.getGlobalKernelHooks(), - context.getKernelHooks()); - - PromptRenderingEvent preRenderingHookResult = kernelHooks - .executeHooks(new PromptRenderingEvent(this, argumentsIn)); - - KernelArguments arguments = preRenderingHookResult.getArguments(); - - // TODO: put in method, add catch for classcastexception, fallback to noopconverter - ContextVariableType variableType = contextVariableType != null - ? contextVariableType - : context.getContextVariableTypes().getVariableTypeForClass( - (Class) this.getMetadata().getOutputVariableType().getType()); - - return this.template - .renderAsync(kernel, arguments, context) - .flatMapMany(prompt -> { - PromptRenderedEvent promptHookResult = kernelHooks - .executeHooks(new PromptRenderedEvent(this, arguments, prompt)); - prompt = promptHookResult.getPrompt(); - KernelArguments args = promptHookResult.getArguments(); - - LOGGER.info(SemanticKernelResources.getString("rendered.prompt"), prompt); - - FunctionInvokingEvent invokingEvent = kernelHooks - .executeHooks(new FunctionInvokingEvent(this, args)); - - args = KernelArguments.builder() - .withVariables(invokingEvent.getArguments()) - .withExecutionSettings(this.getExecutionSettings()) - .build(); - - AIServiceSelection aiServiceSelection = kernel - .getServiceSelector() - .trySelectAIService( - TextAIService.class, - this, - args); - - AIService client = aiServiceSelection != null ? aiServiceSelection.getService() - : null; - if (aiServiceSelection == null) { - throw new IllegalStateException( - "Failed to initialise aiService, could not find any TextAIService implementations"); - } - - Flux> result; - - // settings from prompt or use default - PromptExecutionSettings executionSettings = aiServiceSelection.getSettings(); - - if (client instanceof ChatCompletionService) { - InvocationContext contextWithExecutionSettings = context; - if (context.getPromptExecutionSettings() == null) { - contextWithExecutionSettings = InvocationContext.copy(context) - .withPromptExecutionSettings(executionSettings) - .build(); - } - - result = ((ChatCompletionService) client) - .getChatMessageContentsAsync( - prompt, - kernel, - contextWithExecutionSettings) - .flatMapMany(Flux::fromIterable) - .concatMap(chatMessageContent -> { - if (chatMessageContent.getAuthorRole() == AuthorRole.ASSISTANT) { - - T value = variableType - .getConverter() - .fromObject(chatMessageContent); - - if (value == null) { - value = variableType - .getConverter() - .fromPromptString( - chatMessageContent.getContent()); - } - - if (value == null) { - return Flux.empty(); - } - - return Flux.just( - new FunctionResult<>( - new ContextVariable<>(variableType, value), - chatMessageContent.getMetadata(), - chatMessageContent)); - } - return Flux.empty(); - }) - .map(it -> { - return new FunctionResult<>( - new ContextVariable<>( - variableType, - it.getResult() != null - ? variableType.of(it.getResult()).getValue() - : null), - it.getMetadata(), - it.getUnconvertedResult()); - }); - } else if (client instanceof TextGenerationService) { - result = ((TextGenerationService) client) - .getTextContentsAsync( - prompt, - executionSettings, - kernel) - .flatMapMany(Flux::fromIterable) - .concatMap(textContent -> { - T value = variableType - .getConverter() - .fromObject(textContent); - - if (value == null) { - value = variableType - .getConverter() - .fromPromptString(textContent.getContent()); - } - - return Flux.just( - new FunctionResult<>( - new ContextVariable<>( - variableType, - value), - textContent.getMetadata(), - textContent)); - }); - } else { - return Flux.error(new IllegalStateException("Unknown service type")); - } - - return result - .map(it -> { - FunctionInvokedEvent updatedResult = kernelHooks - .executeHooks( - new FunctionInvokedEvent<>( - this, - arguments, - it)); - - return updatedResult.getResult(); - }); - }) - .doOnError( - ex -> { - LOGGER.warn( - SemanticKernelResources.getString( - "something.went.wrong.while.rendering.the.semantic.function.or.while.executing.the.text.completion.function.error"), - getPluginName(), - getName(), - ex.getMessage()); - - // Common message when you attempt to send text completion - // requests to a chat completion model: - // "logprobs, best_of and echo parameters are not - // available on gpt-35-turbo model" - if (ex instanceof HttpResponseException - && ((HttpResponseException) ex).getResponse().getStatusCode() == 400 - && ex.getMessage() != null - && ex.getMessage().contains("parameters are not available on")) { - LOGGER.warn( - SemanticKernelResources.getString( - "this.error.indicates.that.you.have.attempted.to.use.a.chat.completion.model")); - } - }); - } - - @Override - public Mono> invokeAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable ContextVariableType variableType, - @Nullable InvocationContext invocationContext) { - return Mono.deferContextual(contextView -> { - FunctionSpan span = FunctionSpan.build( - SemanticKernelTelemetry.getTelemetry(invocationContext), - contextView, - this.getPluginName(), - this.getName(), - arguments); - - return invokeInternalAsync(kernel, arguments, variableType, invocationContext) - .contextWrite(span.getReactorContextModifier()) - .takeLast(1) - .single() - .doOnSuccess(span::onFunctionSuccess) - .doOnError(span::onFunctionError) - .doOnTerminate(span::close); - }); - } - - /** - * A builder for creating a {@link KernelFunction} from a prompt template. - * - * @param the type of the return value of the function - */ - public static final class Builder implements FromPromptBuilder { - - @Nullable - private PromptTemplate promptTemplate; - @Nullable - private String name; - @Nullable - private Map executionSettings = null; - @Nullable - private String description; - @Nullable - private List inputVariables; - @Nullable - private String template; - private String templateFormat = PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT; - @Nullable - private OutputVariable outputVariable; - @Nullable - private PromptTemplateFactory promptTemplateFactory; - @Nullable - private PromptTemplateConfig promptTemplateConfig; - - @Override - public FromPromptBuilder withName(@Nullable String name) { - this.name = name; - return this; - } - - @Override - public FromPromptBuilder withInputParameters( - @Nullable List inputVariables) { - if (inputVariables != null) { - this.inputVariables = new ArrayList<>(inputVariables); - } else { - this.inputVariables = null; - } - return this; - } - - @Override - public FromPromptBuilder withPromptTemplate(@Nullable PromptTemplate promptTemplate) { - this.promptTemplate = promptTemplate; - return this; - } - - @Override - public FromPromptBuilder withExecutionSettings( - @Nullable Map executionSettings) { - if (this.executionSettings == null) { - this.executionSettings = new HashMap<>(); - } - - if (executionSettings != null) { - this.executionSettings.putAll(executionSettings); - } - return this; - } - - @Override - public FromPromptBuilder withDefaultExecutionSettings( - @Nullable PromptExecutionSettings executionSettings) { - if (executionSettings == null) { - return this; - } - - if (this.executionSettings == null) { - this.executionSettings = new HashMap<>(); - } - - this.executionSettings.put(PromptExecutionSettings.DEFAULT_SERVICE_ID, - executionSettings); - - if (executionSettings.getServiceId() != null) { - this.executionSettings.put(executionSettings.getServiceId(), executionSettings); - } - return this; - } - - @Override - public FromPromptBuilder withDescription(@Nullable String description) { - this.description = description; - return this; - } - - @Override - public FromPromptBuilder withTemplate(@Nullable String template) { - this.template = template; - return this; - } - - @Override - public FromPromptBuilder withTemplateFormat(String templateFormat) { - this.templateFormat = templateFormat; - return this; - } - - @Override - public FromPromptBuilder withOutputVariable( - @Nullable OutputVariable outputVariable) { - this.outputVariable = outputVariable; - return (FromPromptBuilder) this; - } - - @Override - public FromPromptBuilder withOutputVariable(@Nullable String description, String type) { - return this.withOutputVariable(new OutputVariable(type, description)); - } - - @Override - public FromPromptBuilder withPromptTemplateFactory( - @Nullable PromptTemplateFactory promptTemplateFactory) { - this.promptTemplateFactory = promptTemplateFactory; - return this; - } - - @Override - public FromPromptBuilder withPromptTemplateConfig( - @Nullable PromptTemplateConfig promptTemplateConfig) { - this.promptTemplateConfig = promptTemplateConfig; - return this; - } - - @Override - public KernelFunction build() { - - if (templateFormat == null) { - templateFormat = PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT; - } - - if (name == null) { - name = UUID.randomUUID().toString(); - } - - if (promptTemplateFactory == null) { - promptTemplateFactory = new KernelPromptTemplateFactory(); - } - - if (promptTemplateConfig != null) { - if (promptTemplate == null) { - promptTemplate = promptTemplateFactory.tryCreate(promptTemplateConfig); - } - return new KernelFunctionFromPrompt<>( - promptTemplate, - promptTemplateConfig, - executionSettings); - } - - PromptTemplateConfig config = new PromptTemplateConfig( - name, - template, - templateFormat, - Collections.emptySet(), - description, - inputVariables, - outputVariable, - executionSettings); - - PromptTemplate temp; - if (promptTemplate != null) { - temp = promptTemplate; - } else { - temp = new KernelPromptTemplateFactory().tryCreate(config); - } - - return new KernelFunctionFromPrompt<>(temp, config, executionSettings); - - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionMetadata.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionMetadata.java deleted file mode 100644 index 9ea878861..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionMetadata.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * Metadata about a kernel function. - * - * @param The type of the return value of the function. - */ -public class KernelFunctionMetadata { - - private final String name; - @Nullable - private final String pluginName; - @Nullable - private final String description; - private final List parameters; - private final OutputVariable returnParameterType; - - /** - * Create a new instance of KernelFunctionMetadata. - * - * @param pluginName The name of the plugin to which the function belongs - * @param name The name of the function. - * @param description The description of the function. - * @param parameters The parameters of the function. - * @param returnParameterType The return parameter type of the function. - */ - public KernelFunctionMetadata( - @Nullable String pluginName, - String name, - @Nullable String description, - @Nullable List parameters, - OutputVariable returnParameterType) { - this.pluginName = pluginName; - this.name = name; - this.description = description; - if (parameters == null) { - this.parameters = new ArrayList<>(); - } else { - this.parameters = new ArrayList<>(parameters); - } - - this.returnParameterType = returnParameterType; - } - - /** - * Get the name of the plugin to which the function belongs - * - * @return The name of the function. - */ - @Nullable - public String getPluginName() { - return pluginName; - } - - /** - * Get the name of the function. - * - * @return The name of the function. - */ - public String getName() { - return name; - } - - /** - * Get the parameters of the function. - * - * @return The parameters of the function. - */ - public List getParameters() { - return Collections.unmodifiableList(parameters); - } - - /** - * Get the description of the function. - * - * @return The description of the function. - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Get the return parameter of the function. - * - * @return The return parameter of the function. - */ - public OutputVariable getOutputVariableType() { - return returnParameterType; - } - - @Override - public int hashCode() { - return Objects.hash(name, pluginName, description, parameters, returnParameterType); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!getClass().isInstance(obj)) - return false; - - KernelFunctionMetadata other = (KernelFunctionMetadata) obj; - if (!Objects.equals(name, other.name)) - return false; - if (!Objects.equals(pluginName, other.pluginName)) - return false; - if (!Objects.equals(description, other.description)) - return false; - if (!Objects.equals(parameters, other.parameters)) - return false; - return Objects.equals(returnParameterType, other.returnParameterType); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYaml.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYaml.java deleted file mode 100644 index 2068e50fb..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYaml.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import javax.annotation.Nullable; - -/** - * A class for creating a {@link KernelFunction} instance from a YAML representation of a prompt - * function. - */ -public class KernelFunctionYaml { - - /** - * Create a KernelFunction instance for a prompt function using the specified markdown text. - * - * @param yaml YAML representation of the PromptTemplateConfig to use to create - * the prompt function - * @param promptTemplateFactory Prompt template factory. - * @param The return type of the function. - * @return The created KernelFunction. - * @throws IOException If an error occurs while reading the YAML. - */ - public static KernelFunction fromPromptYaml( - String yaml, - @Nullable PromptTemplateFactory promptTemplateFactory) throws IOException { - try (InputStream targetStream = new ByteArrayInputStream( - yaml.getBytes(StandardCharsets.UTF_8))) { - return fromYaml(targetStream, promptTemplateFactory); - } - } - - /** - * Create a KernelFunction instance for a prompt function using the specified markdown text. - * - * @param yaml YAML representation of the PromptTemplateConfig to use to create the prompt - * function - * @param The return type of the function. - * @return The created KernelFunction. - * @throws IOException If an error occurs while reading the YAML. - */ - public static KernelFunction fromPromptYaml( - String yaml) throws IOException { - return fromPromptYaml(yaml, null); - } - - /** - * Create a KernelFunction instance for a prompt function using the specified markdown text. - * - * @param filePath Path to the YAML representation of the PromptTemplateConfig to use to create - * the prompt function - * @param The return type of the function. - * @return The created KernelFunction. - * @throws IOException If an error occurs while reading the YAML. - */ - public static KernelFunction fromYaml(Path filePath) throws IOException { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - try (InputStream inputStream = classLoader.getResourceAsStream(filePath.toString())) { - return fromYaml(inputStream, null); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static KernelFunction fromYaml( - InputStream inputStream, - @Nullable PromptTemplateFactory promptTemplateFactory) throws IOException { - ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - PromptTemplateConfig functionModel = mapper.readValue(inputStream, - PromptTemplateConfig.class); - - PromptTemplate promptTemplate; - if (promptTemplateFactory == null) { - promptTemplate = PromptTemplateFactory.build(functionModel); - } else { - promptTemplate = promptTemplateFactory.tryCreate(functionModel); - } - - return (KernelFunction) new KernelFunctionFromPrompt.Builder() - .withName(functionModel.getName()) - .withInputParameters(functionModel.getInputVariables()) - .withPromptTemplate(promptTemplate) - .withExecutionSettings(functionModel.getExecutionSettings()) - .withDescription(functionModel.getDescription()) - .withOutputVariable(functionModel.getOutputVariable()) - .build(); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java deleted file mode 100644 index 45dd8428d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory.HANDLEBARS_TEMPLATE_FORMAT; -import static com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.DefaultPromptTemplate; -import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate; -import java.util.Locale; -import javax.annotation.Nonnull; - -/** - * Factory for creating prompt templates. This factory creates the appropriate prompt template based - * on the template format. - */ -public class KernelPromptTemplateFactory implements PromptTemplateFactory { - - /** - * Initializes a new instance of the {@code KernelPromptTemplateFactory} class. - */ - public KernelPromptTemplateFactory() { - } - - @Override - public PromptTemplate tryCreate(@Nonnull PromptTemplateConfig templateConfig) { - if (templateConfig.getTemplate() == null) { - throw new SKException( - String.format("No prompt template was provided for the prompt %s.", - templateConfig.getName())); - } - - switch (templateConfig.getTemplateFormat().toLowerCase(Locale.ROOT)) { - case SEMANTIC_KERNEL_TEMPLATE_FORMAT: - return DefaultPromptTemplate.build(templateConfig); - case HANDLEBARS_TEMPLATE_FORMAT: - return new HandlebarsPromptTemplate(templateConfig); - default: - throw new UnknownTemplateFormatException(templateConfig.getTemplateFormat()); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/MethodDetails.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/MethodDetails.java deleted file mode 100644 index cf957fb42..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/MethodDetails.java +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod.ImplementationFunc; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Metadata for a method that can be used as a kernel function. - */ -public class MethodDetails { - - private final String name; - @Nullable - private final String description; - private final ImplementationFunc function; - private final List parameters; - private final OutputVariable returnParameter; - - /** - * Constructor. - * - * @param name The name of the method. - * @param description The description of the method. - * @param function The function that implements the method. - * @param parameters The parameters of the method. - * @param returnParameter The return parameter of the method. - */ - public MethodDetails( - String name, - @Nullable String description, - ImplementationFunc function, - List parameters, - OutputVariable returnParameter) { - this.name = name; - this.description = description; - this.function = function; - this.parameters = new ArrayList<>(parameters); - this.returnParameter = returnParameter; - } - - /** - * Get the name of the method. - * - * @return The name of the method. - */ - public String getName() { - return name; - } - - /** - * Get the description of the method. - * - * @return The description of the method. - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Get the function that implements the method. This is an internal detail. - * - * @return The function that implements the method. - */ - public ImplementationFunc getFunction() { - return function; - } - - /** - * Get the parameters of the method. - * - * @return The parameters of the method. - */ - public List getParameters() { - return Collections.unmodifiableList(parameters); - } - - /** - * Get the return parameter of the method. - * - * @return The return parameter of the method. - */ - public OutputVariable getReturnParameter() { - return returnParameter; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/OutputVariable.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/OutputVariable.java deleted file mode 100644 index 833aef171..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/OutputVariable.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * Metadata for an output variable of a kernel function. - * @param The type of the output variable. - */ -public class OutputVariable { - - @Nullable - private final String description; - - private final String type; - - /** - * Constructor. - * - * @param type The type of the output variable. - * @param description The description of the output variable. - */ - @JsonCreator - public OutputVariable( - @Nullable @JsonProperty(value = "type", defaultValue = "java.lang.String") String type, - @Nullable @JsonProperty("description") String description) { - this.description = description; - if (type == null || type.isEmpty()) { - type = "java.lang.String"; - } - this.type = type; - } - - /** - * Constructor. - * - * @param type The type of the output variable. - * @param description The description of the output variable. - */ - public OutputVariable( - @Nullable String description, - Class type) { - this.description = description; - this.type = type.getName(); - } - - /** - * Get the description of the output variable. - * - * @return The description of the output variable. - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Get the type of the output variable. - * - * @return The type of the output variable. - */ - public Class getType() { - return KernelPluginFactory.getTypeForName(type); - } - - @Override - public int hashCode() { - return Objects.hash(type, description); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!getClass().isInstance(obj)) { - return false; - } - - OutputVariable that = (OutputVariable) obj; - if (!Objects.equals(type, that.type)) { - return false; - } - return Objects.equals(description, that.description); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java deleted file mode 100644 index 58a5c6a81..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -/** - * Represents a prompt template that can be rendered to a string. - */ -public interface PromptTemplate { - - /** - * Renders the template using the supplied {@code Kernel}, {@code KernelFunctionArguments}, and - * {@code InvocationContext}. - * - * @param kernel The {@link Kernel} containing services, plugins, and other state for use - * throughout the operation. - * @param arguments The arguments to use to satisfy any input variables in the prompt template. - * @param context The {@link InvocationContext} which carries optional information for the - * prompt rendering. - * @return The rendered prompt. - */ - Mono renderAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable InvocationContext context); - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java deleted file mode 100644 index cbc0478ba..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import javax.annotation.Nullable; - -/** - * Metadata for a prompt template. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class PromptTemplateConfig { - - /** - * The current prompt template config schema version. - */ - public static final int CURRENT_SCHEMA = 1; - - /** - * The default name for a prompt template config. - */ - public static final String DEFAULT_CONFIG_NAME = "default"; - - /** - * The default template format for a prompt template config. - */ - public static final String SEMANTIC_KERNEL_TEMPLATE_FORMAT = "semantic-kernel"; - - private final int schema; - @Nullable - private final String name; - @Nullable - private final String template; - private final String templateFormat; - private final Set promptTemplateOptions; - @Nullable - private final String description; - private final List inputVariables; - @Nullable - private final OutputVariable outputVariable; - private final Map executionSettings; - - /** - * Constructor for a prompt template config - * - * @param template Template string - */ - protected PromptTemplateConfig(String template) { - this( - CURRENT_SCHEMA, - DEFAULT_CONFIG_NAME, - template, - SEMANTIC_KERNEL_TEMPLATE_FORMAT, - Collections.emptySet(), - "", - Collections.emptyList(), - new OutputVariable(String.class.getName(), "out"), - Collections.emptyMap()); - } - - /** - * Constructor for a prompt template config - * - * @param schema Schema version - * @param name Name of the template - * @param template Template string - * @param templateFormat Template format - * @param promptTemplateOptions Prompt template options - * @param description Description of the template - * @param inputVariables Input variables - * @param outputVariable Output variable - * @param executionSettings Execution settings - */ - @JsonCreator - public PromptTemplateConfig( - @Nullable @JsonProperty("schema") Integer schema, - @Nullable @JsonProperty("name") String name, - @Nullable @JsonProperty("template") String template, - @Nullable @JsonProperty(value = "template_format", defaultValue = SEMANTIC_KERNEL_TEMPLATE_FORMAT) String templateFormat, - @Nullable @JsonProperty(value = "prompt_template_options") Set promptTemplateOptions, - @Nullable @JsonProperty("description") String description, - @Nullable @JsonProperty("input_variables") List inputVariables, - @Nullable @JsonProperty("output_variable") OutputVariable outputVariable, - @Nullable @JsonProperty("execution_settings") Map executionSettings) { - if (schema == null) { - schema = CURRENT_SCHEMA; - } - this.schema = schema; - this.name = name; - this.template = template; - if (templateFormat == null) { - templateFormat = SEMANTIC_KERNEL_TEMPLATE_FORMAT; - } - this.templateFormat = templateFormat; - if (promptTemplateOptions == null) { - promptTemplateOptions = new HashSet<>(); - } - this.promptTemplateOptions = promptTemplateOptions; - this.description = description; - if (inputVariables == null) { - this.inputVariables = new ArrayList<>(); - } else { - this.inputVariables = new ArrayList<>(inputVariables); - } - this.outputVariable = outputVariable != null - ? outputVariable - : new OutputVariable(String.class.getName(), "out"); - if (executionSettings == null) { - this.executionSettings = new HashMap<>(); - } else { - this.executionSettings = new HashMap<>(executionSettings); - } - } - - /** - * Constructor for a prompt template config - * - * @param name Name of the template - * @param template Template string - * @param templateFormat Template format - * @param description Description of the template - * @param inputVariables Input variables - * @param outputVariable Output variable - * @param executionSettings Execution settings - */ - protected PromptTemplateConfig( - @Nullable String name, - @Nullable String template, - @Nullable String templateFormat, - @Nullable Set promptTemplateOptions, - @Nullable String description, - @Nullable List inputVariables, - @Nullable OutputVariable outputVariable, - @Nullable Map executionSettings) { - this( - CURRENT_SCHEMA, - name, - template, - templateFormat, - promptTemplateOptions, - description, - inputVariables, - outputVariable, - executionSettings); - } - - /** - * Copy constructor. - * - * @param promptTemplate The prompt template to copy. - */ - public PromptTemplateConfig(PromptTemplateConfig promptTemplate) { - this( - promptTemplate.name, - promptTemplate.template, - promptTemplate.templateFormat, - promptTemplate.promptTemplateOptions, - promptTemplate.description, - promptTemplate.inputVariables, - promptTemplate.outputVariable, - promptTemplate.executionSettings); - } - - /** - * Deserialize the JSON string to a PromptTemplateConfig. - * - * @param json The JSON string to parse - * @return The PromptTemplateConfig object - * @throws SKException If the prompt template config cannot be deserialized. - */ - public static PromptTemplateConfig parseFromJson(String json) throws SKException { - try { - return new ObjectMapper().readValue(json, PromptTemplateConfig.class); - } catch (JsonProcessingException e) { - throw new SKException("Unable to parse prompt template config", e); - } - } - - /** - * Create a builder for a prompt template config. - * - * @return The prompt template config builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a builder for a prompt template config, where the constructed template will be - * considered the default to be used if no other config is selected. - * - * @return The default prompt template config. - */ - public static Builder defaultTemplateBuilder() { - return new Builder() - .withName(DEFAULT_CONFIG_NAME); - } - - /** - * Get the parameters metadata. - * - * @return The parameters metadata. - */ - public List getKernelParametersMetadata() { - if (inputVariables == null) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(inputVariables); - } - - /** - * Get the return parameter metadata. - * - * @return The return parameter metadata. - */ - public OutputVariable getKernelReturnParameterMetadata() { - if (outputVariable == null) { - return new OutputVariable<>("", String.class); - } - - return new OutputVariable<>( - outputVariable.getDescription(), - outputVariable.getType()); - } - - /** - * Get the name of the prompt template config. - * - * @return The name of the prompt template config. - */ - @Nullable - public String getName() { - return name; - } - - /** - * Get the template of the prompt template config. - * - * @return The template of the prompt template config. - */ - @Nullable - public String getTemplate() { - return template; - } - - /** - * Get the description of the prompt template config. - * - * @return The description of the prompt template config. - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Get the inputVariables of the prompt template config. - * - * @return The input variables of the prompt template config. - */ - public List getInputVariables() { - return Collections.unmodifiableList(inputVariables); - } - - /** - * Get the output variable of the prompt template config. - * - * @return The output variable of the prompt template config. - */ - @Nullable - public OutputVariable getOutputVariable() { - return outputVariable; - } - - /** - * Get the prompt execution settings of the prompt template config. - * - * @return The prompt execution settings of the prompt template config. - */ - @Nullable - public Map getExecutionSettings() { - if (executionSettings != null) { - return Collections.unmodifiableMap(executionSettings); - } - return null; - } - - /** - * Get the template format of the prompt template config. - * - * @return The template format of the prompt template config. - */ - public String getTemplateFormat() { - return templateFormat; - } - - /** - * Get the schema version of the prompt template config. - * - * @return The schema version of the prompt template config. - */ - public int getSchema() { - return schema; - } - - /** - * Get the prompt template options of the prompt template config. - * - * @return The prompt template options of the prompt template config. - */ - public Set getPromptTemplateOptions() { - return Collections.unmodifiableSet(promptTemplateOptions); - } - - /** - * Create a builder for a prompt template config which is a clone of the current object. - * - * @return The prompt template config builder. - */ - public Builder copy() { - return new Builder(this); - } - - @Override - public int hashCode() { - return Objects.hash(name, template, templateFormat, description, inputVariables, - outputVariable, executionSettings); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!getClass().isInstance(obj)) { - return false; - } - final PromptTemplateConfig other = (PromptTemplateConfig) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!Objects.equals(this.template, other.template)) { - return false; - } - if (!Objects.equals(this.description, other.description)) { - return false; - } - if (!Objects.equals(this.templateFormat, other.templateFormat)) { - return false; - } - if (!Objects.equals(this.inputVariables, other.inputVariables)) { - return false; - } - if (!Objects.equals(this.outputVariable, other.outputVariable)) { - return false; - } - return Objects.equals(this.executionSettings, other.executionSettings); - } - - /** - * Builder for a prompt template config. - */ - public static class Builder { - - @Nullable - private String name; - @Nullable - private String template; - private String templateFormat = SEMANTIC_KERNEL_TEMPLATE_FORMAT; - private final Set promptTemplateOptions = new HashSet<>(); - @Nullable - private String description = null; - private List inputVariables = new ArrayList<>(); - @Nullable - private OutputVariable outputVariable; - private Map executionSettings = new HashMap<>(); - - private Builder() { - } - - private Builder(PromptTemplateConfig promptTemplateConfig) { - this.name = promptTemplateConfig.name; - this.template = promptTemplateConfig.template; - this.templateFormat = promptTemplateConfig.templateFormat; - this.description = promptTemplateConfig.description; - this.inputVariables = new ArrayList<>(promptTemplateConfig.inputVariables); - this.outputVariable = promptTemplateConfig.outputVariable; - this.executionSettings = new HashMap<>(promptTemplateConfig.executionSettings); - } - - /** - * Set the name of the prompt template config. - * - * @param name The name of the prompt template config. - * @return {@code this} builder - */ - public Builder withName(String name) { - this.name = name; - return this; - } - - /** - * Add an input variable to the prompt template config. - * - * @param inputVariable The input variable to add. - * @return {@code this} builder - */ - public Builder addInputVariable(InputVariable inputVariable) { - inputVariables.add(inputVariable); - return this; - } - - /** - * Set the template of the prompt template config. - * - * @param template The template of the prompt template config. - * @return {@code this} builder - */ - public Builder withTemplate(String template) { - this.template = template; - return this; - } - - /** - * Set the description of the prompt template config. - * - * @param description The description of the prompt template config. - * @return {@code this} builder - */ - public Builder withDescription(String description) { - this.description = description; - return this; - } - - /** - * Set the template format of the prompt template config. - * - * @param templateFormat The template format of the prompt template config. - * @return {@code this} builder - */ - public Builder withTemplateFormat(String templateFormat) { - this.templateFormat = templateFormat; - return this; - } - - /** - * Set the prompt template options. - * @param option The prompt template option to add. - * @return {@code this} builder. - */ - public Builder addPromptTemplateOption(PromptTemplateOption option) { - promptTemplateOptions.add(option); - return this; - } - - /** - * Set the inputVariables of the prompt template config. - * - * @param inputVariables The input variables of the prompt template config. - * @return {@code this} builder - */ - public Builder withInputVariables(List inputVariables) { - this.inputVariables = new ArrayList<>(inputVariables); - return this; - } - - /** - * Set the output variable of the prompt template config. - * - * @param outputVariable The output variable of the prompt template config. - * @return {@code this} builder - */ - public Builder withOutputVariable(OutputVariable outputVariable) { - this.outputVariable = outputVariable; - return this; - } - - /** - * Set the prompt execution settings of the prompt template config. - * - * @param executionSettings The prompt execution settings of the prompt template config. - * @return {@code this} builder - */ - public Builder withExecutionSettings( - Map executionSettings) { - this.executionSettings = new HashMap<>(executionSettings); - return this; - } - - /** - * Build the prompt template config. - * - * @return The prompt template config. - */ - public PromptTemplateConfig build() { - return new PromptTemplateConfig( - name, - template, - templateFormat, - promptTemplateOptions, - description, - inputVariables, - outputVariable, - executionSettings); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactory.java deleted file mode 100644 index 5546b8c9d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import javax.annotation.Nullable; - -/** - * The interface that a {@code PromptTemplateFactory} implementation must provide. - */ -public interface PromptTemplateFactory { - - /** - * Create a prompt template, if possible, from the given configuration. This is a convenience - * method that wraps the {@link KernelPromptTemplateFactory#tryCreate(PromptTemplateConfig)} - * method. - * - * @param templateConfig The configuration for the prompt template. - * @return The prompt template. - * @throws UnknownTemplateFormatException If the template format is not supported. - * @see PromptTemplateConfig#getTemplateFormat() - */ - static PromptTemplate build(PromptTemplateConfig templateConfig) { - return new KernelPromptTemplateFactory().tryCreate(templateConfig); - } - - /** - * Create a prompt template, if possible, from the given configuration. If the - * {@code PromptTemplateConfig} is not supported, the method should throw an - * {@code UnknownTemplateFormatException}. - * - * @param templateConfig The configuration for the prompt template. - * @return The prompt template. - * @throws UnknownTemplateFormatException If the template format is not supported. - * @see PromptTemplateConfig#getTemplateFormat() - */ - PromptTemplate tryCreate(PromptTemplateConfig templateConfig); - - /** - * Exception thrown when the template format is not supported. - * - * @see PromptTemplateConfig#getTemplateFormat() - */ - class UnknownTemplateFormatException extends IllegalArgumentException { - - /** - * Constructor. - * - * @param templateFormat The template format that is not supported. - */ - public UnknownTemplateFormatException(@Nullable String templateFormat) { - super("Unknown template format: " + templateFormat); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateOption.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateOption.java deleted file mode 100644 index 56f5a2e26..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateOption.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -/** - * Options to customize the behavior of a prompt. - */ -public enum PromptTemplateOption { - /** - * Allow methods on objects provided as arguments to an invocation, to be invoked when rendering - * a template and its return value used. Typically, this would be used to call a getter on an - * object i.e. {@code {{#each users}} {{userName}} {{/each}} } on a handlebars template will - * call the method {@code getUserName()} on each object in {@code users}. - *

- * WARNING: If this option is used, ensure that your template is trusted, and that objects added - * as arguments to an invocation, do not contain methods that are unsafe to be invoked when - * rendering a template. - */ - ALLOW_CONTEXT_VARIABLE_METHOD_CALLS_UNSAFE -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/DefineKernelFunction.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/DefineKernelFunction.java deleted file mode 100644 index 8df2dc14c..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/DefineKernelFunction.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that defines a method that can be invoked as a native function - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface DefineKernelFunction { - - /** - * The description of what the function does. The description should be short and concise. The - * model uses the description to determine whether the function is a good match for use to - * complete a prompt. If the model is not selecting a function when it should be, consider - * adding more detail to the description. - * - * @return the description of the function, or an empty string if no description is provided. - */ - String description() default ""; - - /** - * The name of the function. - * - * @return the name of the function, or an empty string if no name is provided. - */ - String name() default ""; - - /** - * The fully qualified class name of the return value of the function, for example, - * "java.lang.String". If this parameter is not provided, the model will attempt to infer the - * return type from the method signature. For async methods provide the return from the async - * method, i.e. if the method returns a Mono<String> then the returnType should be "java.lang.String". - * - * @return the fully qualified class name of the return value of the function - */ - String returnType() default ""; - - /** - * The description of the return value of the function. The description should be short and - * concise. - * - * @return the description of the return value of the function, or an empty string if no - * description is provided. - */ - String returnDescription() default ""; - - /** - * Examples of how to use the function. The examples should be short and concise. The Semantic - * Kernel can use the examples to help the model understand how the function is used. - * - * @return Examples of how to use the function, or an empty array if no examples are provided. - */ - - SKSample[] samples() default {}; -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/KernelFunctionParameter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/KernelFunctionParameter.java deleted file mode 100644 index 25bbe83cd..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/KernelFunctionParameter.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions.annotations; - -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a parameter to a native function - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface KernelFunctionParameter { - - /** - * A special value that is used to indicate that no default value is provided. - */ - String NO_DEFAULT_VALUE = "SKFunctionParameters__NO_INPUT_PROVIDED"; - - /** - * The description of the parameter. The description should be short and concise. The model uses - * the description to determine what value to pass to the function. - * - * @return the description of the parameter, or an empty string if no description is provided. - */ - String description() default ""; - - /** - * The name of the parameter. This element is required. - * - * @return the name of the parameter, or an empty string if no name is provided. - */ - String name(); - - /** - * The default value of the parameter. If no value is set, {@code null} will be passed as the - * value to this argument. - * - * @return the default value of the parameter, or - * {@link KernelFunctionParameter#NO_DEFAULT_VALUE} if no default value is provided. - */ - String defaultValue() default NO_DEFAULT_VALUE; - - /** - * Whether a value is required for this argument. If required is false, the model is free to - * choose whether to provide a value. If the model does not provide a value, the default value - * is used. - * - * @return whether a value is required for this argument. - */ - boolean required() default true; - - /** - * The type of the parameter. The Semantic Kernel will use the type to find a - * {@link ContextVariableType} to convert the value from a prompt string to the correct argument - * type. The type defaults to {@link String} if not provided. - * - * @return the type of the parameter - */ - Class type() default String.class; -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/SKSample.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/SKSample.java deleted file mode 100644 index 5b3f5ea38..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/annotations/SKSample.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that decorates an {@link DefineKernelFunction} annotation to provide examples of how - * to use the function. For example: - *


- * {@literal @}DefineSKFunction(
- *    name = "add",
- *    description = "Adds two numbers together",
- *    returnType = "java.lang.Integer",
- *    returnDescription = "The sum of the two numbers",
- *    samples = {
- *        {@literal @}SKSample(inputs = "{\"number1\":1, \"number2\":2", output = "3")
- *     }
- *  )
- * public static double add(
- *       {@literal @}SKFunctionParameters(description="The first number to add", name="number1") double number1,
- *       {@literal @}SKFunctionParameters(description="The second number to add", name="number2") double number2
- *   )
- *   {
- *       return number1 + number2;
- *   }
- * 
- */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface SKSample { - - /** - * An example of inputs to the function. - * - * @return An example of inputs to the function. - */ - String inputs(); - - /** - * An example output of the function given the inputs. - * - * @return An example output of the function given the inputs. - */ - String output(); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceCollection.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceCollection.java deleted file mode 100644 index 48d9def78..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceCollection.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import java.util.HashMap; - -/** - * A collection of AI services. - */ -public class AIServiceCollection extends HashMap, AIService> { - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelection.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelection.java deleted file mode 100644 index 8e139b872..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelection.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import javax.annotation.Nullable; - -/** - * The result of an AI service selection. - * - * @param The type of AI service. - */ -public class AIServiceSelection { - - private final T service; - @Nullable - private final PromptExecutionSettings settings; - - /** - * Creates a new AI service selection. - * - * @param service The selected AI service. - * @param settings The settings associated with the selected service. This may be {@code null} - * even if a service is selected.. - */ - public AIServiceSelection(T service, @Nullable PromptExecutionSettings settings) { - this.service = service; - this.settings = settings; - } - - /** - * Gets the selected AI service. - * - * @return The selected AI service. - */ - public T getService() { - return service; - } - - /** - * Gets the settings associated with the selected service. - * - * @return The settings associated with the selected service. This may be {@code null} even if a - * service is selected. - */ - @Nullable - public PromptExecutionSettings getSettings() { - return settings; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java deleted file mode 100644 index ac95f7d35..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import javax.annotation.Nullable; - -/** - * Represents a selector which will return an {@link AIServiceSelection} containing instances of - * {@link AIService} and {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings} - * from the specified provider based on the model settings. - */ -public interface AIServiceSelector { - - /** - * Resolves an {@link AIService} and associated and - * {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings} based on the - * associated {@link KernelFunction} and {@link KernelArguments}. - * - * @param serviceType The type of service to select. This must be the same type with which the - * service was registered in the {@link AIServiceSelection} - * @param function The KernelFunction to use to select the service, or {@code null}. - * @param arguments The KernelArguments to use to select the service, or - * {@code null}. - * @param The type of service to select. - * @return An {@code AIServiceSelection} containing the selected service and associated - * PromptExecutionSettings. - */ - @Nullable - AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelFunction function, - @Nullable KernelArguments arguments); - - /** - * Resolves an {@link AIService} and associated and - * {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings} based on the - * associated {@link KernelFunction} and {@link KernelArguments}. - * - * @param serviceType The type of service to select. This must be the same type with which the - * service was registered in the {@link AIServiceSelection} - * @param arguments The KernelArguments to use to select the service, or - * {@code null}. - * @param The type of service to select. - * @return An {@code AIServiceSelection} containing the selected service and associated - * PromptExecutionSettings. - */ - @Nullable - default AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelArguments arguments) { - throw new UnsupportedOperationException( - "This method is not implemented."); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java deleted file mode 100644 index b022bf358..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Base class for {@link AIServiceSelector} implementations which provides a {@code Map} based - * collection from which an {@link AIService} can be selected. The - * {@link #trySelectAIService(Class, KernelFunction, KernelArguments)} method has been - * implemented. Child classes must implement the method - * {@link #trySelectAIService(Class, KernelFunction, KernelArguments, Map)}. - */ -public abstract class BaseAIServiceSelector implements AIServiceSelector { - - protected final AIServiceCollection services; - - /** - * Initializes a new instance of the {@link BaseAIServiceSelector} class. - * - * @param services The services to select from. - */ - protected BaseAIServiceSelector(AIServiceCollection services) { - this.services = services; - } - - @Override - @Nullable - public AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelFunction function, - @Nullable KernelArguments arguments) { - return trySelectAIService(serviceType, function, arguments, services); - } - - @Override - @Nullable - public AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelArguments arguments) { - return trySelectAIService(serviceType, arguments, services); - } - - /** - * Resolves an {@link AIService} from the {@code services} argument using the specified - * {@code function} and {@code arguments} for selection. - * - * @param serviceType The type of service to select. This must be the same type with which the - * service was registered in the {@link AIServiceSelection} - * @param function The KernelFunction to use to select the service, or {@code null}. - * @param arguments The KernelFunctionArguments to use to select the service, or - * {@code null}. - * @param services The services to select from. - * @param The type of service to select. - * @return The selected service, or {@code null} if no service could be selected. - * - */ - @Nullable - protected abstract AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelFunction function, - @Nullable KernelArguments arguments, - Map, AIService> services); - - /** - * Resolves an {@link AIService} from the {@code services} argument using the specified - * {@code function} and {@code arguments} for selection. - * - * @param serviceType The type of service to select. This must be the same type with which the - * service was registered in the {@link AIServiceSelection} - * @param arguments The KernelArguments to use to select the service, or - * {@code null}. - * @param services The services to select from. - * @param The type of service to select. - * @return The selected service, or {@code null} if no service could be selected. - */ - @Nullable - protected AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelArguments arguments, - Map, AIService> services) { - return trySelectAIService(serviceType, null, arguments, services); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContent.java deleted file mode 100644 index 6c8c80bc7..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContent.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import javax.annotation.Nullable; - -/** - * Base class which represents the content returned by an AI service. - * - * @param The type of the content. - */ -public interface KernelContent { - - /** - * The inner content representation. Use this to bypass the current - * abstraction. The usage of this property is considered "unsafe". - * Use it only if strictly necessary. - * @return The inner content. - */ - @Nullable - T getInnerContent(); - - /** - * The metadata associated with the content. - * @return The metadata. - */ - @Nullable - FunctionResultMetadata getMetadata(); - - /** - * Gets the content returned by the AI service. - * - * @return The content. - */ - @Nullable - String getContent(); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContentImpl.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContentImpl.java deleted file mode 100644 index e83e909df..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/KernelContentImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import javax.annotation.Nullable; - -/** - * Base class which represents the content returned by an AI service. - * - * @param The type of the content. - */ -public abstract class KernelContentImpl implements KernelContent { - - /* - * The inner content representation. Use this to bypass the current - * abstraction. The usage of this property is considered "unsafe". - * Use it only if strictly necessary. - */ - @Nullable - private final T innerContent; - - /** - * The model ID used to generate the content. - */ - @Nullable - private final String modelId; - - /** - * The metadata associated with the content. - */ - @Nullable - private final FunctionResultMetadata metadata; - - /** - * Initializes a new instance of the {@link KernelContentImpl} class. - * - * @param innerContent The inner content representation. - * @param modelId The model identifier used to generate the content. - * @param metadata The metadata associated with the content. - */ - public KernelContentImpl( - @Nullable T innerContent, - @Nullable String modelId, - @Nullable FunctionResultMetadata metadata) { - this.innerContent = innerContent; - this.modelId = modelId; - this.metadata = metadata; - } - - /** - * Initializes a new instance of the {@link KernelContentImpl} class. - */ - public KernelContentImpl() { - this(null, null, null); - } - - /** - * Gets the inner content representation. - * - * @return The inner content representation. - */ - @Nullable - @Override - public T getInnerContent() { - return innerContent; - } - - /** - * Gets the metadata associated with the content. - * - * @return The metadata associated with the content. - */ - @Nullable - @Override - public FunctionResultMetadata getMetadata() { - return metadata; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/NamedServiceProvider.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/NamedServiceProvider.java deleted file mode 100644 index 8745f054d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/NamedServiceProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import javax.annotation.Nullable; - -/** - * A service provider for named services. - * - * @param The type of the service. - */ -public interface NamedServiceProvider { - - /** - * Gets the service of the specified type and name, or {@code null} if not found. - * - * @param name The name of the service, or {@code null} for the default service. - * @param clazz The type of the service. - * @param The specific type of the service - * @return The service instance, or {@code null} if not found. - */ - @Nullable - public U getService(@Nullable String name, Class clazz); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java deleted file mode 100644 index 30828233d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.implementation.Verify; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; -import com.microsoft.semantickernel.services.textcompletion.TextGenerationService; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of {@link com.microsoft.semantickernel.services.AIServiceSelector} that selects - * the AI service based on the order of the execution settings. Uses the service id or model id to - * select the preferred service provider and then returns the service and associated execution - * settings. - */ -public class OrderedAIServiceSelector extends BaseAIServiceSelector { - - private static final Logger LOGGER = LoggerFactory.getLogger(OrderedAIServiceSelector.class); - - /** - * Initializes a new instance of the {@link OrderedAIServiceSelector} class with an empty - * collection of services. - */ - public OrderedAIServiceSelector() { - super(new AIServiceCollection()); - } - - /** - * Initializes a new instance of the {@link OrderedAIServiceSelector} class with the specified - * services. - * - * @param services The services to select from. - */ - public OrderedAIServiceSelector(AIServiceCollection services) { - super(services); - } - - @SuppressWarnings("unchecked") - @Nullable - private static AIServiceSelection castServiceSelection( - AIServiceSelection selection) { - try { - // unchecked cast - return (AIServiceSelection) selection; - } catch (ClassCastException e) { - LOGGER.debug("{}", e.getMessage()); - return null; - } - } - - @Nullable - @Override - public AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelFunction function, - @Nullable KernelArguments arguments, - Map, AIService> services) { - - if (function == null) { - return selectAIService(serviceType, - arguments != null ? arguments.getExecutionSettings() : null); - } - - return selectAIService(serviceType, function.getExecutionSettings()); - } - - private AIServiceSelection selectAIService( - Class serviceType, - @Nullable Map executionSettings) { - - if (executionSettings == null || executionSettings.isEmpty()) { - AIService service = getAnyService(serviceType); - if (service != null) { - return castServiceSelection(new AIServiceSelection<>(service, null)); - } - } else { - AIServiceSelection selection = executionSettings - .entrySet() - .stream() - .map(keyValue -> { - - PromptExecutionSettings settings = keyValue.getValue(); - String serviceId = keyValue.getKey(); - - if (!Verify.isNullOrEmpty(serviceId)) { - AIService service = getService(serviceId); - if (service != null) { - return castServiceSelection( - new AIServiceSelection<>(service, settings)); - } - } - - return null; - }) - .filter(Objects::nonNull) - .findFirst() - .orElseGet(() -> null); - - if (selection != null) { - return castServiceSelection(selection); - } - - selection = executionSettings - .entrySet() - .stream() - .map(keyValue -> { - PromptExecutionSettings settings = keyValue.getValue(); - - if (!Verify.isNullOrEmpty(settings.getModelId())) { - AIService service = getServiceByModelId(settings.getModelId()); - if (service != null) { - return castServiceSelection( - new AIServiceSelection<>(service, settings)); - } - } - - return null; - }) - .filter(Objects::nonNull) - .findFirst() - .orElseGet(() -> null); - - if (selection != null) { - return castServiceSelection(selection); - } - } - - AIService defaultService = getService(PromptExecutionSettings.DEFAULT_SERVICE_ID); - - if (defaultService != null && serviceType.isAssignableFrom(defaultService.getClass())) { - return castServiceSelection(new AIServiceSelection<>(defaultService, null)); - } - - AIService service = getAnyService(serviceType); - PromptExecutionSettings settings = null; - - if (executionSettings != null && !executionSettings.isEmpty()) { - if (executionSettings.containsKey(PromptExecutionSettings.DEFAULT_SERVICE_ID)) { - settings = executionSettings.get(PromptExecutionSettings.DEFAULT_SERVICE_ID); - } else { - settings = executionSettings.values().stream().findFirst().orElseGet(() -> null); - } - } - - if (service != null) { - return castServiceSelection(new AIServiceSelection<>(service, settings)); - } - - LOGGER.warn(SemanticKernelResources.getString("no.service.found.meeting.requirements")); - return null; - } - - private AIService getServiceByModelId(String modelId) { - return services - .values() - .stream() - .filter(s -> modelId.equalsIgnoreCase(s.getModelId())) - .findFirst() - .orElseGet(() -> null); - } - - /** - * Gets the service with the specified service id. - * - * @param serviceId The service id. - * @return The service with the specified service id, or {@code null} if no such service exists. - * @see AIService#getServiceId() - */ - @Nullable - public AIService getService(String serviceId) { - return services - .values() - .stream() - .filter(s -> serviceId.equalsIgnoreCase(s.getServiceId())) - .findFirst() - .orElseGet(() -> null); - } - - /** - * Gets the service of the specified type. - * - * @param clazz The type of service to get. - * @param The type of service to get. - * @return The service of the specified type, or {@code null} if no such service exists. - */ - @Nullable - @SuppressWarnings("unchecked") - public T getService(Class clazz) { - T service = (T) services.get(clazz); - - if (service == null) { - service = (T) services - .entrySet() - .stream() - .filter(it -> clazz.isAssignableFrom(it.getKey())) - .map(it -> it.getValue()) - .findFirst() - .orElseGet(() -> null); - } - - if (service == null && - (clazz.equals(TextGenerationService.class) || - clazz.equals(ChatCompletionService.class))) { - LOGGER.warn( - SemanticKernelResources.getString( - "requested.a.non.existent.service.type.of.consider.requesting.a.textaiservice.instead"), - clazz.getName()); - } - - return service; - } - - /** - * Gets the first service of the specified type, or that is an instance of the specified type. - * - * @param serviceType The type of service to get. - * @return The first service of the specified type, or {@code null} if no such service exists. - */ - @Nullable - AIService getAnyService(Class serviceType) { - List matchingServices = getServices(serviceType); - if (matchingServices.isEmpty()) { - return null; - } - return matchingServices.get(0); - } - - private List getServices(Class serviceType) { - return services - .entrySet() - .stream() - .filter(it -> serviceType.isAssignableFrom(it.getKey())) - .map(Map.Entry::getValue) - .collect(Collectors.toList()); - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/ServiceNotFoundException.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/ServiceNotFoundException.java deleted file mode 100644 index 3209d89ef..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/ServiceNotFoundException.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.exceptions.SKCheckedException; - -/** - * Exception thrown when a service is not found. - */ -public class ServiceNotFoundException extends SKCheckedException { - - /** - * Initializes a new instance of the {@link ServiceNotFoundException} class. - * - * @param s A message which describes the service that could not be found. - */ - public ServiceNotFoundException(String s) { - super(s); - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingKernelContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingKernelContent.java deleted file mode 100644 index dd1dcffe5..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingKernelContent.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -/** - * Base class which represents the content returned by an AI service. - * @param The type of the content. - */ -public interface StreamingKernelContent extends KernelContent { - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingTextContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingTextContent.java deleted file mode 100644 index 95e784491..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/StreamingTextContent.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Base class which represents the content returned by a streaming AI service. - * - * @param The type of the content. - */ -public abstract class StreamingTextContent extends KernelContentImpl implements - StreamingKernelContent { - - /** - * In a scenario of multiple choices per request, this represents the zero-based index of the - * choice in the streaming sequence - */ - private final int choiceIndex; - - /** - * Initializes a new instance of the {@link StreamingTextContent} class. - * - * @param innerContent The inner content representation. - * @param choiceIndex The zero-based index of the choice in the streaming sequence. - * @param modelId The model identifier used to generate the content. - * @param metadata The metadata associated with the content. - */ - protected StreamingTextContent( - @Nullable T innerContent, - int choiceIndex, - @Nullable String modelId, - @Nullable Map> metadata) { - super(innerContent, modelId, null); - this.choiceIndex = choiceIndex; - } - - /** - * Gets the zero-based index of the choice in the streaming sequence. - * - * @return The zero-based index of the choice in the streaming sequence. - */ - public int getChoiceIndex() { - return choiceIndex; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/TextAIService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/TextAIService.java deleted file mode 100644 index 3eee32d36..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/TextAIService.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -/** - * Marker interface for Text AI services, typically Chat or Text generation for OpenAI - */ -public interface TextAIService extends AIService { - - /** - * The maximum number of results per prompt - */ - int MAX_RESULTS_PER_PROMPT = 128; - - /** - * The maximum number of auto-invokes that can be in-flight at any given time as part of the - * current asynchronous chain of execution. - *

- * This is a fail-safe mechanism. If someone accidentally manages to set up execution settings - * in such a way that auto-invocation is invoked recursively, and in particular where a prompt - * function is able to auto-invoke itself, we could end up in an infinite loop. This const is a - * backstop against that happening. We should never come close to this limit, but if we do, - * auto-invoke will be disabled for the current flow in order to prevent runaway execution. With - * the current setup, the way this could possibly happen is if a prompt function is configured - * with built-in execution settings that opt-in to auto-invocation of everything in the kernel, - * in which case the invocation of that prompt function could advertise itself as a candidate - * for auto-invocation. We don't want to outright block that, if that's something a developer - * has asked to do (e.g. it might be invoked with different arguments than its parent was - * invoked with), but we do want to limit it. This limit is arbitrary and can be tweaked in the - * future and/or made configurable should need arise. - *

- */ - int MAXIMUM_INFLIGHT_AUTO_INVOKES = 128; -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioContent.java deleted file mode 100644 index cc06bded3..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioContent.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.audio; - -import com.microsoft.semantickernel.exceptions.SKException; -import java.util.Arrays; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Represents audio content. - */ -public class AudioContent { - - private final byte[] data; - @Nullable - private final String modelId; - - /** - * Creates an instance of audio content. - * - * @param data The audio data. - * @param modelId The model ID. - */ - public AudioContent(byte[] data, @Nullable String modelId) { - this.data = Arrays.copyOf(data, data.length); - this.modelId = modelId; - } - - /** - * Gets the audio data. - * - * @return The audio data. - */ - public byte[] getData() { - return Arrays.copyOf(data, data.length); - } - - /** - * Gets the model ID. - * - * @return The model ID. - */ - @Nullable - public String getModelId() { - return modelId; - } - - /** - * Gets the inner content. - * - * @return The inner content. - */ - @Nullable - public String getInnerContent() { - return null; - } - - /** - * Gets the metadata. - * - * @return The metadata. - */ - @Nullable - public Map getMetadata() { - return null; - } - - /** - * Creates a new builder. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Represents a builder for audio content. - */ - public static class Builder { - - @Nullable - private byte[] data = null; - @Nullable - private String modelId = null; - - /** - * Sets the audio data. - * - * @param data The audio data. - * @return The builder. - */ - public Builder withData(byte[] data) { - this.data = Arrays.copyOf(data, data.length); - return this; - } - - /** - * Sets the model ID. - * - * @param modelId The model ID. - * @return The builder. - */ - public Builder withModelId(String modelId) { - this.modelId = modelId; - return this; - } - - /** - * Builds the audio content. - * - * @return The audio content. - */ - public AudioContent build() { - if (data == null) { - throw new SKException("Data is required"); - } - - if (modelId == null) { - throw new SKException("Model ID is required"); - } - - return new AudioContent(data, modelId); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextExecutionSettings.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextExecutionSettings.java deleted file mode 100644 index c70555b9e..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextExecutionSettings.java +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.audio; - -import javax.annotation.Nullable; - -/** - * Represents audio content. - */ -public class AudioToTextExecutionSettings { - - @Nullable - private final String deploymentName; - - @Nullable - private final String filename; - - private final String responseFormat; - - @Nullable - private final String language; - - @Nullable - private final String prompt; - - @Nullable - private final Double temperature; - - /** - * Creates an instance of audio to text execution settings. - * - * @param deploymentName The deployment name. - * @param filename The filename. - * @param responseFormat The response format. - * @param language The language. - * @param prompt The prompt. - * @param temperature The temperature. - */ - public AudioToTextExecutionSettings( - @Nullable String deploymentName, - @Nullable String filename, - String responseFormat, - @Nullable String language, - @Nullable String prompt, - @Nullable Double temperature) { - this.deploymentName = deploymentName; - this.filename = filename; - this.responseFormat = responseFormat; - this.language = language; - this.prompt = prompt; - this.temperature = temperature; - } - - /** - * The deployment name to use for audio transcription. - *

- * When making a request against Azure OpenAI, this should be the customizable name of the - * "model deployment" (example: my-gpt4-deployment) and not the name of the model itself - * (example: gpt-4). - *

- * When using non-Azure OpenAI, this corresponds to "model" in the request options and should - * use the appropriate name of the model (example: gpt-4). - * - * @return The deployment name. - */ - @Nullable - public String getDeploymentName() { - return deploymentName; - } - - /** - * The optional filename or descriptive identifier to associate with the audio data. - * - * @return The filename or descriptive identifier. - */ - @Nullable - public String getFilename() { - return filename; - } - - /** - * The requested format of the transcription response data, which will influence the content and - * detail of the result. - * - * @return The response format. - */ - public String getResponseFormat() { - return responseFormat; - } - - /** - * The language of the audio data as two-letter ISO-639-1 language code (e.g. 'en' or 'es'). - * - * @return The language of the audio data. - */ - @Nullable - public String getLanguage() { - return language; - } - - /** - * An optional hint to guide the model's style or continue from a prior audio segment. The - * written language of the prompt should match the primary spoken language of the audio data. - * - * @return The prompt. - */ - @Nullable - public String getPrompt() { - return prompt; - } - - /** - * The randomness of the generated text. Select a value from 0.0 to 1.0. 0 is the default. - * - * @return The temperature. - */ - @Nullable - public Double getTemperature() { - return temperature; - } - - /** - * Creates a new builder. - * - * @return The builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Represents a builder for audio to text execution settings. - */ - public static class Builder { - - @Nullable - private String deploymentName = null; - @Nullable - private String filename = null; - @Nullable - private String responseFormat = null; - @Nullable - private String language = null; - @Nullable - private String prompt = null; - @Nullable - private Double temperature = null; - - /** - * Sets the deployment name to use for audio transcription. - * - * @param deploymentName The deployment name. - * @return The builder. - */ - public Builder withDeploymentName(String deploymentName) { - this.deploymentName = deploymentName; - return this; - } - - /** - * Sets the filename or descriptive identifier to associate with the audio data. - * - * @param filename The filename or descriptive identifier. - * @return The builder. - */ - public Builder withFilename(String filename) { - this.filename = filename; - return this; - } - - /** - * The requested format of the transcription response data, which will influence the content - * and detail of the result. - * - * @param responseFormat The response format. Supported formats are json, text, srt, - * verbose_json, or vtt. Default is 'json'. - * @return The builder. - */ - public Builder withResponseFormat(String responseFormat) { - this.responseFormat = responseFormat; - return this; - } - - /** - * The language of the audio data as two-letter ISO-639-1 language code (e.g. 'en' or - * 'es'). - * - * @param language The language of the audio data. - * @return The builder. - */ - public Builder withLanguage(String language) { - this.language = language; - return this; - } - - /** - * An optional hint to guide the model's style or continue from a prior audio segment. The - * written language of the prompt should match the primary spoken language of the audio - * data. - * - * @param prompt The prompt. - * @return The builder. - */ - public Builder withPrompt(String prompt) { - this.prompt = prompt; - return this; - } - - /** - * The randomness of the generated text. Select a value from 0.0 to 1.0. 0 is the default. - * - * @param temperature The temperature. - * @return The builder. - */ - public Builder withTemperature(Double temperature) { - this.temperature = temperature; - return this; - } - - /** - * Builds the audio to text execution settings. - * - * @return The audio to text execution settings. - */ - public AudioToTextExecutionSettings build() { - if (responseFormat == null) { - responseFormat = "json"; - } - - return new AudioToTextExecutionSettings(deploymentName, filename, - responseFormat, language, prompt, temperature); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextService.java deleted file mode 100644 index deeec0f64..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/AudioToTextService.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.audio; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.microsoft.semantickernel.implementation.ServiceLoadUtil; -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder; -import javax.annotation.Nullable; -import reactor.core.publisher.Mono; - -/** - * Provides audio to text service. - */ -public interface AudioToTextService extends AIService { - - /** - * Get text contents from audio content. - * - * @param content Audio content. - * @param executionSettings The AI execution settings (optional). - * @return Text contents from audio content. - */ - Mono getTextContentsAsync( - AudioContent content, - @Nullable AudioToTextExecutionSettings executionSettings); - - /** - * Builder for the AudioToTextService. - * @return The builder. - */ - static Builder builder() { - return ServiceLoadUtil.findServiceLoader(Builder.class, - "com.microsoft.semantickernel.aiservices.openai.audio.OpenAiAudioToTextService$Builder") - .get(); - } - - /** - * Builder for the AudioToTextService. - */ - abstract class Builder - extends OpenAiServiceBuilder { - - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioExecutionSettings.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioExecutionSettings.java deleted file mode 100644 index f85659c54..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioExecutionSettings.java +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.audio; - -import com.microsoft.semantickernel.exceptions.SKException; -import edu.umd.cs.findbugs.annotations.Nullable; - -/** - * Represents the settings for text to audio execution. - */ -public class TextToAudioExecutionSettings { - - private final String voice; - private final String responseFormat; - @Nullable - private final Double speed; - - /** - * Creates a new instance of the settings. - * - * @param voice The voice. - * @param responseFormat The response format. - * @param speed The speed. - */ - public TextToAudioExecutionSettings( - String voice, - String responseFormat, - @Nullable Double speed) { - this.voice = voice; - this.responseFormat = responseFormat; - this.speed = speed; - } - - /** - * Gets the voice. - * - * @return The voice. - */ - public String getVoice() { - return voice; - } - - /** - * Gets the response format. - * - * @return The response format. - */ - public String getResponseFormat() { - return responseFormat; - } - - /** - * Gets the speed. - * - * @return The speed. - */ - @Nullable - public Double getSpeed() { - return speed; - } - - /** - * Creates a new builder. - * - * @return The builder. - */ - public static TextToAudioExecutionSettings.Builder builder() { - return new Builder(); - } - - /** - * Represents a builder for text to audio execution settings. - */ - public static class Builder { - - @Nullable - private String voice = null; - @Nullable - private String responseFormat = null; - @Nullable - private Double speed = null; - - /** - * Sets the voice to use for the audio generation. - * - * @param voice The voice. - * @return The builder. - */ - public Builder withVoice(String voice) { - this.voice = voice; - return this; - } - - /** - * Sets the response format, e.g "mp3", "opus", "aac", "flak" - * - * @param responseFormat The response format. - * @return The builder. - */ - public Builder withResponseFormat(String responseFormat) { - this.responseFormat = responseFormat; - return this; - } - - /** - * Sets the speed of the audio generation. - * - * @param speed The speed. - * @return The builder. - */ - public Builder withSpeed(Double speed) { - this.speed = speed; - return this; - } - - /** - * Builds the settings. - * - * @return The settings. - */ - public TextToAudioExecutionSettings build() { - if (voice == null) { - throw new SKException("Voice must be set"); - } - if (responseFormat == null) { - throw new SKException("Response format must be set"); - } - return new TextToAudioExecutionSettings(voice, responseFormat, speed); - } - - private Builder() { - } - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioService.java deleted file mode 100644 index ff2cd40a0..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/audio/TextToAudioService.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.audio; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.microsoft.semantickernel.implementation.ServiceLoadUtil; -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder; -import reactor.core.publisher.Mono; - -/** - * Provides audio to text service. - */ -public interface TextToAudioService extends AIService { - - /** - * Get audio content from text. - * - * @param sampleText The sample text. - * @param executionSettings The AI execution settings. - * @return Audio content from text. - */ - Mono getAudioContentAsync(String sampleText, - TextToAudioExecutionSettings executionSettings); - - /** - * Gets the builder for the TextToAudioService. - * - * @return The builder. - */ - static Builder builder() { - return ServiceLoadUtil.findServiceLoader(Builder.class, - "com.microsoft.semantickernel.aiservices.openai.audio.OpenAiTextToAudioService$Builder") - .get(); - } - - /** - * Builder for the TextToAudioService. - */ - abstract class Builder extends - OpenAiServiceBuilder { - - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/AuthorRole.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/AuthorRole.java deleted file mode 100644 index 745a1050f..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/AuthorRole.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion; - -/** - * Role of the author of a chat message - */ -public enum AuthorRole { - - /** - * A system message helps set the behavior of the assistant. - */ - SYSTEM("system"), - /** - * An assistant message is a message generated by the assistant. - */ - ASSISTANT("assistant"), - /** - * A user message is a message generated by the user. - */ - USER("user"), - - /** - * A tool message is a message generated by a tool. - */ - TOOL("tool"); - - private final String role; - - private AuthorRole(String role) { - this.role = role; - } - - @Override - public String toString() { - return role; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatCompletionService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatCompletionService.java deleted file mode 100644 index d1655c05d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatCompletionService.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.services.TextAIService; -import java.util.List; -import javax.annotation.Nullable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * Chat completion service interface. - */ -public interface ChatCompletionService extends TextAIService { - /** - * Gets the chat message contents asynchronously using {@code ChatHistory} to support a - * turn-based conversation. Typically, the resulting chat message contents is appended to the - * {@code chatHistory} to continue the conversation. - * - * @param chatHistory the chat history - * @param kernel the kernel - * @param invocationContext the invocation context - * @return the chat message contents - */ - Mono>> getChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext); - - /** - * Gets the chat message contents asynchronously using a prompt. - * - * @param prompt the prompt - * @param kernel the kernel - * @param invocationContext the invocation context - * @return the chat message contents - */ - Mono>> getChatMessageContentsAsync( - String prompt, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext); - - /** - * Gets the chat message contents asynchronously using {@code ChatHistory} to support a - * turn-based conversation. Typically, the resulting chat message contents is appended to the - * {@code chatHistory} to continue the conversation. - * - * @param chatHistory the chat history - * @param kernel the kernel - * @param invocationContext the invocation context - * @return the chat message contents - */ - Flux> getStreamingChatMessageContentsAsync( - ChatHistory chatHistory, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext); - - /** - * Gets the chat message contents asynchronously using a prompt. - * - * @param prompt the prompt - * @param kernel the kernel - * @param invocationContext the invocation context - * @return the chat message contents - */ - Flux> getStreamingChatMessageContentsAsync( - String prompt, - @Nullable Kernel kernel, - @Nullable InvocationContext invocationContext); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java deleted file mode 100644 index df5f18322..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatHistory.java +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Spliterator; -import java.util.function.Consumer; -import javax.annotation.Nullable; - -/** - * Provides a history of messages between the User, Assistant and System - */ -public class ChatHistory implements Iterable> { - - private final List> chatMessageContents; - - /** - * The default constructor - */ - public ChatHistory() { - this((String) null); - } - - /** - * Constructor that adds the given system instructions to the chat history. - * - * @param instructions The instructions to add to the chat history - */ - public ChatHistory(@Nullable String instructions) { - this.chatMessageContents = Collections.synchronizedList(new ArrayList<>()); - if (instructions != null) { - this.chatMessageContents.add( - ChatMessageTextContent.systemMessage(instructions)); - } - } - - /** - * Constructor that adds the given chat message contents to the chat history. - * - * @param chatMessageContents The chat message contents to add to the chat history - */ - public ChatHistory(List> chatMessageContents) { - this.chatMessageContents = Collections - .synchronizedList(new ArrayList<>(chatMessageContents)); - } - - /** - * Get the chat history - * - * @return List of messages in the chat - */ - public List> getMessages() { - return Collections.unmodifiableList(new ArrayList<>(chatMessageContents)); - } - - /** - * Get last message - * - * @return The most recent message in chat - */ - public Optional> getLastMessage() { - if (chatMessageContents.isEmpty()) { - return Optional.empty(); - } - return Optional - .of(chatMessageContents.get(chatMessageContents.size() - 1)); - } - - /** - * Add all messages from the given chat history to this chat history - * - * @param value The chat history to add to this chat history - */ - public void addAll(ChatHistory value) { - this.chatMessageContents.addAll(value.getMessages()); - } - - /** - * Create an {@code Iterator} from the chat history. - * @return An {@code Iterator} from the chat history. - */ - @Override - public Iterator> iterator() { - return chatMessageContents.iterator(); - } - - /** - * Perform the given action for each message in the chat history - * - * @param action The action to perform for each message in the chat history - */ - @Override - public void forEach(Consumer> action) { - chatMessageContents.forEach(action); - } - - /** - * Create a {@code Spliterator} from the chat history - * @return A {@code Spliterator} from the chat history - */ - @Override - public Spliterator> spliterator() { - return chatMessageContents.spliterator(); - } - - /** - * Add a message to the chat history - * - * @param authorRole The role of the author of the message - * @param content The content of the message - * @param encoding The encoding of the message - * @param metadata The metadata of the message - * @return {@code this} ChatHistory - */ - public ChatHistory addMessage(AuthorRole authorRole, String content, Charset encoding, - FunctionResultMetadata metadata) { - chatMessageContents.add( - ChatMessageTextContent.builder() - .withAuthorRole(authorRole) - .withContent(content) - .withEncoding(encoding) - .withMetadata(metadata) - .build()); - return this; - } - - /** - * Add a message to the chat history - * - * @param authorRole The role of the author of the message - * @param content The content of the message - * @return {@code this} ChatHistory - */ - public ChatHistory addMessage(AuthorRole authorRole, String content) { - chatMessageContents.add( - ChatMessageTextContent.builder() - .withAuthorRole(authorRole) - .withContent(content) - .build()); - return this; - } - - /** - * Add a message to the chat history - * - * @param content The content of the message - * @return {@code this} ChatHistory - */ - public ChatHistory addMessage(ChatMessageContent content) { - chatMessageContents.add(content); - return this; - } - - /** - * Add a user message to the chat history - * - * @param content The content of the user message - * @return {@code this} ChatHistory - */ - public ChatHistory addUserMessage(String content) { - return addMessage(AuthorRole.USER, content); - } - - /** - * Add an assistant message to the chat history - * - * @param content The content of the assistant message - * @return {@code this} ChatHistory - */ - public ChatHistory addAssistantMessage(String content) { - return addMessage(AuthorRole.ASSISTANT, content); - } - - /** - * Add an system message to the chat history - * - * @param content The content of the system message - * @return {@code this} ChatHistory - */ - public ChatHistory addSystemMessage(String content) { - return addMessage(AuthorRole.SYSTEM, content); - } - - /** - * Clear the chat history - */ - public void clear() { - chatMessageContents.clear(); - } - - /** - * Add all messages to the chat history - * @param messages The messages to add to the chat history - * @return {@code this} ChatHistory - */ - public ChatHistory addAll(List> messages) { - chatMessageContents.addAll(messages); - return this; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java deleted file mode 100644 index 2d4ce4911..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/ChatMessageContent.java +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.KernelContent; -import com.microsoft.semantickernel.services.KernelContentImpl; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageContentType; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Represents the content of a chat message - *

- * This class defaults to a {@link ChatMessageContentType#TEXT} content type if none is specified. - * However, if using this for text content, consider using - * {@link com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent} and - * its builders instead. - * - * @param the type of the inner content within the messages - */ -public class ChatMessageContent extends KernelContentImpl { - private final AuthorRole authorRole; - @Nullable - private final String content; - @Nullable - private final List> items; - @Nullable - private final Charset encoding; - private final ChatMessageContentType contentType; - - /** - * Creates a new instance of the {@link ChatMessageContent} class. Defaults to - * {@link ChatMessageContentType#TEXT} content type. - * - * @param authorRole the author role that generated the content - * @param content the content - */ - public ChatMessageContent( - AuthorRole authorRole, - String content) { - this( - authorRole, - content, - null, - null, - null, - null); - } - - /** - * Creates a new instance of the {@link ChatMessageContent} class. Defaults to - * {@link ChatMessageContentType#TEXT} content type. - * - * @param authorRole the author role that generated the content - * @param authorName the author name - * @param content the content - */ - public ChatMessageContent( - AuthorRole authorRole, - String authorName, - String content) { - this( - authorRole, - authorName, - content, - null, - null, - null, - null); - } - - /** - * Creates a new instance of the {@link ChatMessageContent} class. Defaults to - * {@link ChatMessageContentType#TEXT} content type. - * - * @param authorRole the author role that generated the content - * @param content the content - * @param modelId the model id - * @param innerContent the inner content - * @param encoding the encoding - * @param metadata the metadata - */ - public ChatMessageContent( - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable T innerContent, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata) { - this(authorRole, content, modelId, innerContent, encoding, metadata, - ChatMessageContentType.TEXT); - } - - /** - * Creates a new instance of the {@link ChatMessageContent} class. - * - * @param authorRole the author role that generated the content - * @param content the content - * @param modelId the model id - * @param innerContent the inner content - * @param encoding the encoding - * @param metadata the metadata - * @param contentType the content type - */ - public ChatMessageContent( - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable T innerContent, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata, - ChatMessageContentType contentType) { - super(innerContent, modelId, metadata); - this.authorRole = authorRole; - this.content = content; - this.encoding = encoding != null ? encoding : StandardCharsets.UTF_8; - this.items = null; - this.contentType = contentType; - } - - /** - * Creates a new instance of the {@link ChatMessageContent} class. - * - * @param authorRole the author role that generated the content - * @param items the items - * @param modelId the model id - * @param innerContent the inner content - * @param encoding the encoding - * @param metadata the metadata - * @param contentType the content type - */ - public ChatMessageContent( - AuthorRole authorRole, - @Nullable List> items, - String modelId, - T innerContent, - Charset encoding, - FunctionResultMetadata metadata, - ChatMessageContentType contentType) { - super(innerContent, modelId, metadata); - this.content = null; - this.authorRole = authorRole; - this.encoding = encoding != null ? encoding : StandardCharsets.UTF_8; - if (items == null) { - this.items = null; - } else { - this.items = new ArrayList<>(items); - } - this.contentType = contentType; - } - - /** - * Creates a new instance of the {@link ChatMessageContent} class. - * - * @param authorRole the author role that generated the content - * @param items the items - * @param modelId the model id - * @param innerContent the inner content - * @param encoding the encoding - * @param metadata the metadata - */ - public ChatMessageContent( - AuthorRole authorRole, - @Nullable String content, - @Nullable List> items, - String modelId, - T innerContent, - Charset encoding, - FunctionResultMetadata metadata) { - super(innerContent, modelId, metadata); - this.content = content; - this.authorRole = authorRole; - this.encoding = encoding != null ? encoding : StandardCharsets.UTF_8; - if (items == null) { - this.items = null; - } else { - this.items = new ArrayList<>(items); - } - this.contentType = ChatMessageContentType.TEXT; - } - - /** - * Gets the author role that generated the content - * - * @return the author role that generated the content - */ - public AuthorRole getAuthorRole() { - return authorRole; - } - - /** - * Gets the content - * - * @return the content, which may be {@code null} - */ - @Nullable - @Override - public String getContent() { - return content; - } - - /** - * Gets the {@code KernelContent} items that comprise the content. - * - * @return the items, which may be {@code null} - */ - @Nullable - public List> getItems() { - if (items == null) { - return null; - } - return Collections.unmodifiableList(items); - } - - /** - * Gets the encoding of the content - * - * @return the encoding, which may be {@code null} - */ - @Nullable - public Charset getEncoding() { - return encoding; - } - - /** - * Gets the content type - * - * @return the content type - */ - public ChatMessageContentType getContentType() { - return contentType; - } - - @Override - public String toString() { - return content != null ? content : ""; - } - -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/StreamingChatContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/StreamingChatContent.java deleted file mode 100644 index 52bb4131b..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/StreamingChatContent.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion; - -import com.microsoft.semantickernel.services.StreamingKernelContent; - -/** - * Base class which represents the content returned by a chat completion service. - * @param The type of the content. - */ -public interface StreamingChatContent extends StreamingKernelContent { - - /** - * Gets the ID of the content. - * @return The ID. - */ - public String getId(); -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageContentType.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageContentType.java deleted file mode 100644 index 2845deb0d..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageContentType.java +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion.message; - -/** - * Represents the content of a chat message - */ -public enum ChatMessageContentType { - /** - * The content is text - */ - TEXT, - /** - * The content is an image - */ - IMAGE_URL -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageImageContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageImageContent.java deleted file mode 100644 index 75ab0a3dd..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageImageContent.java +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion.message; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.net.URL; -import java.util.Base64; -import javax.annotation.Nullable; - -/** - * Represents an image content in a chat message. - * - * @param the type of the inner content within the message - */ -public class ChatMessageImageContent extends ChatMessageContent { - - private final ImageDetail detail; - - /** - * Create a new instance of the {@link ChatMessageImageContent} class. - * @param content The chat message content - * @param modelId The LLM id to use for the chat - * @param detail The detail level of the image to include in the chat message - */ - public ChatMessageImageContent( - String content, - @Nullable String modelId, - @Nullable ImageDetail detail) { - super( - AuthorRole.USER, - content, - modelId, - null, - null, - null, - ChatMessageContentType.IMAGE_URL); - - if (detail == null) { - detail = ImageDetail.AUTO; - } - this.detail = detail; - } - - /** - * Get the detail level of the image to include in the chat message. - * - * @return the detail level of the image - */ - public ImageDetail getDetail() { - return detail; - } - - /** - * The detail level of the image to include in the chat message. - */ - public enum ImageDetail { - /** - * Low detail - */ - LOW, - /** - * High detail - */ - HIGH, - /** - * Automatically determine the detail level - */ - AUTO - } - - /** - * Create a new builder for the {@link ChatMessageImageContent} class. - * - * @param the type of the inner content within the messages - * @return a new builder - */ - public static Builder builder() { - return new Builder<>(); - } - - /** - * Builder for the {@link ChatMessageImageContent} class. - * @param the type of the inner content within the message - */ - public static class Builder implements SemanticKernelBuilder> { - - @Nullable - private String modelId = null; - @Nullable - private String content = null; - @Nullable - private ImageDetail detail = null; - - /** - * Set the model ID to use for the chat message. - * - * @param modelId the model ID - * @return {@code this} builder - */ - public Builder withModelId(String modelId) { - this.modelId = modelId; - return this; - } - - /** - * Set the image content to include in the chat message. - * @param imageType For instance jpg or png. For known types known to OpenAI see: docs. - * @param content the image content - * @return {@code this} builder - */ - public Builder withImage( - String imageType, - byte[] content) { - this.content = String.format("data:image/%s;base64,%s", - imageType, - Base64.getEncoder().encodeToString(content)); - return this; - } - - /** - * Set the URL of the image to include in the chat message. - * - * @param url the URL of the image - * @return {@code this} builder - */ - public Builder withImageUrl(String url) { - this.content = url; - return this; - } - - /** - * Set the URL of the image to include in the chat message. - * - * @param url the URL of the image - * @return {@code this} builder - */ - public Builder withImageUrl(URL url) { - this.content = url.toString(); - return this; - } - - /** - * Set the detail level of the image to include in the chat message. - * - * @param detail the detail level of the image - * @return {@code this} builder - */ - public Builder withDetail(ImageDetail detail) { - this.detail = detail; - return this; - } - - @Override - public ChatMessageImageContent build() { - if (detail == null) { - detail = ImageDetail.AUTO; - } - if (content == null) { - throw new SKException("Image content is required"); - } - return new ChatMessageImageContent<>( - content, - modelId, - detail); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageTextContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageTextContent.java deleted file mode 100644 index f065ed2ff..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/chatcompletion/message/ChatMessageTextContent.java +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.chatcompletion.message; - -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.KernelContent; -import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import java.nio.charset.Charset; -import java.util.List; -import javax.annotation.Nullable; - -/** - * Represents the content of a chat message which contains text - */ -public class ChatMessageTextContent extends ChatMessageContent { - - /** - * Creates a new instance of the {@link ChatMessageTextContent} class. - * - * @param authorRole the author role that generated the content - * @param content the content - * @param modelId the model id - * @param encoding the encoding of the content - * @param metadata the metadata - */ - public ChatMessageTextContent( - AuthorRole authorRole, - String content, - @Nullable String modelId, - @Nullable Charset encoding, - @Nullable FunctionResultMetadata metadata) { - super(authorRole, content, modelId, null, encoding, metadata, - ChatMessageContentType.TEXT); - } - - /** - * Create a new builder for the {@link ChatMessageTextContent} class. - * - * @return a new builder - */ - public static Builder builder() { - return new Builder(); - } - - private static ChatMessageTextContent buildContent(AuthorRole role, String content) { - return new Builder() - .withAuthorRole(role) - .withContent(content) - .build(); - } - - /** - * Create a message with the author role set to {@link AuthorRole#USER} - * - * @param content The content of the message - * @return The message - */ - public static ChatMessageTextContent userMessage(String content) { - return buildContent(AuthorRole.USER, content); - } - - /** - * Create a message with the author role set to {@link AuthorRole#ASSISTANT} - * - * @param content The content of the message - * @return The message - */ - public static ChatMessageTextContent assistantMessage(String content) { - return buildContent(AuthorRole.ASSISTANT, content); - } - - /** - * Create a message with the author role set to {@link AuthorRole#SYSTEM} - * - * @param content The content of the message - * @return The message - */ - public static ChatMessageTextContent systemMessage(String content) { - return buildContent(AuthorRole.SYSTEM, content); - } - - /** - * Builder for the {@link ChatMessageTextContent} class. - */ - public static class Builder implements SemanticKernelBuilder { - - @Nullable - private String modelId = null; - @Nullable - private FunctionResultMetadata metadata = null; - @Nullable - private AuthorRole authorRole = null; - @Nullable - private String content = null; - @Nullable - private List> items = null; - @Nullable - private Charset encoding = null; - - /** - * Set the content of the message - * - * @param content The content of the message - * @return The builder - */ - public Builder withContent(String content) { - this.content = content; - return this; - } - - /** - * Set the model ID used to generate the content - * - * @param modelId The model ID - * @return The builder - */ - public Builder withModelId(String modelId) { - this.modelId = modelId; - return this; - } - - /** - * Set the metadata associated with the content - * - * @param metadata The metadata - * @return The builder - */ - public Builder withMetadata(FunctionResultMetadata metadata) { - this.metadata = metadata; - return this; - } - - /** - * Set the author role of the message - * - * @param authorRole The author role - * @return The builder - */ - public Builder withAuthorRole(AuthorRole authorRole) { - this.authorRole = authorRole; - return this; - } - - /** - * Set the encoding of the message - * - * @param encoding The encoding - * @return The builder - */ - public Builder withEncoding(Charset encoding) { - this.encoding = encoding; - return this; - } - - @Override - public ChatMessageTextContent build() { - if (authorRole == null) { - throw new SKException("Author role must be set"); - } - if (content == null) { - throw new SKException("Content must be set"); - } - return new ChatMessageTextContent( - authorRole, - content, - modelId, - encoding, - metadata); - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/openai/OpenAiServiceBuilder.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/openai/OpenAiServiceBuilder.java deleted file mode 100644 index 5386cd839..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/openai/OpenAiServiceBuilder.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.openai; - -import com.microsoft.semantickernel.services.AIService; -import com.microsoft.semantickernel.builders.SemanticKernelBuilder; -import javax.annotation.Nullable; - -/** - * Builder for an OpenAI service. - * @param The client type - * @param The service type - * @param The builder type -*/ -public abstract class OpenAiServiceBuilder> - implements - - SemanticKernelBuilder { - - @Nullable - protected String modelId; - @Nullable - protected C client; - @Nullable - protected String serviceId; - @Nullable - protected String deploymentName; - - /** - * Sets the model ID for the service. - *

- * If no deployment name is provided, it will be assumed that this model ID is also the - * deployment name. - * - * @param modelId The model ID - * @return The builder - */ - public U withModelId(String modelId) { - this.modelId = modelId; - return (U) this; - } - - /** - * Sets the deployment name for the service if required. - * - * @param deploymentName The deployment name - * @return The builder - */ - public U withDeploymentName(String deploymentName) { - this.deploymentName = deploymentName; - return (U) this; - } - - /** - * Sets the OpenAI client for the service - * - * @param client The OpenAI client - * @return The builder - */ - public U withOpenAIAsyncClient(C client) { - this.client = client; - return (U) this; - } - - /** - * Sets the service ID for the service - * - * @param serviceId The service ID - * @return The builder - */ - public U withServiceId(String serviceId) { - this.serviceId = serviceId; - return (U) this; - } - - /** - * Builds the service. - * @return The service - */ - @Override - public abstract T build(); - -} \ No newline at end of file diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextContent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextContent.java deleted file mode 100644 index 3cca884dd..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextContent.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.textcompletion; - -import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; -import com.microsoft.semantickernel.services.KernelContentImpl; -import javax.annotation.Nullable; - -/** - * Content from a text completion service. - */ -public class TextContent extends KernelContentImpl { - - private final String content; - - /** - * Initializes a new instance of the {@code TextContent} class with a provided content, model - * ID, and metadata. - * - * @param content The content. - * @param modelId The model ID. - * @param metadata The metadata. - */ - public TextContent( - String content, - @Nullable String modelId, - @Nullable FunctionResultMetadata metadata) { - super(content, modelId, metadata); - this.content = content; - } - - /** - * Gets the content. - * - * @return The content. - */ - public String getValue() { - return content; - } - - @Override - public String getContent() { - return content; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextGenerationService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextGenerationService.java deleted file mode 100644 index 39fdd5149..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/textcompletion/TextGenerationService.java +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services.textcompletion; - -import com.azure.ai.openai.OpenAIAsyncClient; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.implementation.ServiceLoadUtil; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.services.StreamingTextContent; -import com.microsoft.semantickernel.services.TextAIService; -import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder; -import java.util.List; -import javax.annotation.Nullable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * Interface for text completion services - */ -public interface TextGenerationService extends TextAIService { - - /** - * Get the builder for the TextGenerationService - * - * @return The builder - */ - static Builder builder() { - return ServiceLoadUtil.findServiceLoader(Builder.class, - "com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService$Builder") - .get(); - } - - /** - * Creates a completion for the prompt and settings. - * - * @param prompt The prompt to complete. - * @param executionSettings Request settings for the completion API - * @param kernel The {@code Kernel} containing services, plugins, and other state for - * use throughout the operation. - * @return Text generated by the remote model - */ - Mono> getTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel); - - /** - * Get streaming results for the prompt using the specified execution settings. Each modality - * may support for different types of streaming contents. - * - * @param prompt The prompt to complete. - * @param executionSettings The AI execution settings (optional). - * @param kernel The {@code Kernel} containing services, plugins, and other state for - * use throughout the operation. - * @return Streaming list of different completion streaming string updates generated by the - * remote model - */ - Flux getStreamingTextContentsAsync( - String prompt, - @Nullable PromptExecutionSettings executionSettings, - @Nullable Kernel kernel); - - /** - * Builder for a TextGenerationService - */ - abstract class Builder - extends OpenAiServiceBuilder { - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java deleted file mode 100644 index 460e48159..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.templateengine.handlebars; - -import static com.microsoft.semantickernel.semanticfunctions.KernelArguments.MAIN_KEY; - -import com.github.jknack.handlebars.Context; -import com.github.jknack.handlebars.EscapingStrategy; -import com.github.jknack.handlebars.Handlebars; -import com.github.jknack.handlebars.Helper; -import com.github.jknack.handlebars.Options; -import com.github.jknack.handlebars.ValueResolver; -import com.github.jknack.handlebars.context.JavaBeanValueResolver; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.orchestration.ToolCallBehavior; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateOption; -import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.apache.commons.text.StringEscapeUtils; -import reactor.core.publisher.Mono; - -/** - * A prompt template that uses the Handlebars template engine to render prompts. - */ -public class HandlebarsPromptTemplate implements PromptTemplate { - - private final PromptTemplateConfig promptTemplate; - - /** - * Initializes a new instance of the {@link HandlebarsPromptTemplate} class. - * - * @param promptTemplate The prompt template configuration. - */ - public HandlebarsPromptTemplate( - @Nonnull PromptTemplateConfig promptTemplate) { - this.promptTemplate = new PromptTemplateConfig(promptTemplate); - } - - @Override - public Mono renderAsync( - Kernel kernel, - @Nullable KernelArguments arguments, - @Nullable InvocationContext context) { - String template = promptTemplate.getTemplate(); - if (template == null) { - return Mono.error(new SKException( - String.format("No prompt template was provided for the prompt %s.", - promptTemplate.getName()))); - } - - if (context == null) { - context = InvocationContext.builder().build(); - } - HandleBarsPromptTemplateHandler handler = new HandleBarsPromptTemplateHandler(kernel, - template, context); - - if (arguments == null) { - arguments = KernelArguments.builder().build(); - } - return handler.render(arguments); - } - - private static class MessageResolver implements ValueResolver { - - @Override - @SuppressWarnings("NullAway") - public Object resolve(Object context, String name) { - if (context instanceof ChatMessageContent) { - if ("role".equalsIgnoreCase(name)) { - return ((ChatMessageContent) context).getAuthorRole().name(); - } else if ("content".equalsIgnoreCase(name)) { - return ((ChatMessageContent) context).getContent(); - } - } - return UNRESOLVED; - } - - @Override - public Object resolve(Object context) { - if (context instanceof ChatMessageContent) { - String content = ((ChatMessageContent) context).getContent(); - - if (content == null) { - return UNRESOLVED; - } - - return String.format( - "%s", - ((ChatMessageContent) context).getAuthorRole().toString() - .toLowerCase(Locale.ROOT), - ContextVariableTypeConverter.escapeXmlString(content)); - } - return UNRESOLVED; - } - - @Override - public Set> propertySet(Object context) { - if (context instanceof ChatMessageContent) { - HashMap result = new HashMap<>(); - result.put("role", ((ChatMessageContent) context).getAuthorRole().name()); - result.put("content", ((ChatMessageContent) context).getContent()); - return result.entrySet(); - } - return new HashSet<>(); - } - } - - private static class ContextVariableResolver implements ValueResolver { - - @Override - public Object resolve(Object context, String name) { - Object value = null; - ContextVariable variable = null; - if (context instanceof KernelArguments) { - variable = ((KernelArguments) context).get(name); - } else if (context instanceof ContextVariable) { - variable = ((ContextVariable) context); - } - - if (variable == null || variable.getValue() == null) { - return UNRESOLVED; - } - - value = variable.getValue(); - - if (value instanceof Iterable) { - return value; - } else { - // It is likely this will come escaped, but will be re escaped by the handlebars engine - return promptString(variable); - } - } - - @Override - public Object resolve(Object context) { - if (context instanceof ContextVariable) { - Object result = ((ContextVariable) context).getValue(); - - if (result == null) { - return UNRESOLVED; - } else if (result instanceof Iterable) { - return result; - } else { - return promptString(((ContextVariable) context)); - } - } - return UNRESOLVED; - } - - private String promptString(ContextVariable context) { - // This will come escaped, but will be re escaped by the handlebars engine - return StringEscapeUtils.unescapeXml(context.toPromptString()); - } - - @Override - public Set> propertySet(Object context) { - if (context instanceof KernelArguments) { - HashMap result = new HashMap<>(); - result.putAll((KernelArguments) context); - return result.entrySet(); - } else if (context instanceof ContextVariable) { - HashMap result = new HashMap<>(); - result.put("value", ((ContextVariable) context).getValue()); - return result.entrySet(); - } - return new HashSet<>(); - } - } - - private class HandleBarsPromptTemplateHandler { - - private final String template; - private final Handlebars handlebars; - - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") // Think this is a false positive - public HandleBarsPromptTemplateHandler( - Kernel kernel, - String template, - InvocationContext context) { - this.template = template; - this.handlebars = new Handlebars(); - this.handlebars - .registerHelper("message", this::handleMessage) - .registerHelper("each", handleEach(context)) - .with(EscapingStrategy.XML); - - addFunctionHelpers(kernel, this.handlebars, context); - - // TODO: 1.0 Add more helpers - } - - private Helper handleEach(InvocationContext invocationContext) { - return (variable, options) -> { - if (variable instanceof ContextVariable) { - return ((ContextVariable) variable) - .toPromptString(invocationContext.getContextVariableTypes()); - } - - if (variable instanceof Iterable) { - StringBuilder sb = new StringBuilder(); - - for (Object element : (Iterable) variable) { - if (element instanceof KernelPlugin) { - KernelPlugin plugin = (KernelPlugin) element; - for (KernelFunction function : plugin) { - sb.append(options.fn(function)); - } - } else { - sb.append(options.fn(element)); - } - } - return new Handlebars.SafeString(sb.toString()); - } - - ContextVariableType type = invocationContext.getContextVariableTypes() - .getVariableTypeForClass(variable.getClass()); - if (type != null) { - return type - .getConverter() - .toPromptString(invocationContext.getContextVariableTypes(), variable); - } - return null; - }; - } - - @Nullable - private CharSequence handleMessage(Object context, Options options) - throws IOException { - String role = options.hash("role"); - String content = (String) options.fn(context); - - if (context instanceof Optional) { - ChatMessageContent message = ((Optional) context).orElse( - null); - if (message != null) { - if (role == null || role.isEmpty()) { - role = message.getAuthorRole().name(); - } - content = message.getContent(); - } - } - - if (role != null && !role.isEmpty()) { - return new Handlebars.SafeString( - String.format( - "%s", - role.toLowerCase(Locale.ROOT), - content)); - } - return null; - } - - public Mono render(KernelArguments variables) { - try { - ArrayList resolvers = new ArrayList<>(); - resolvers.add(new MessageResolver()); - resolvers.add(new ContextVariableResolver()); - - if (promptTemplate.getPromptTemplateOptions() - .contains(PromptTemplateOption.ALLOW_CONTEXT_VARIABLE_METHOD_CALLS_UNSAFE)) { - resolvers.add(JavaBeanValueResolver.INSTANCE); - } - - Context context = Context - .newBuilder(variables) - .resolver(resolvers.toArray(new ValueResolver[0])) - .build(); - - String result = handlebars.compileInline(template).apply(context); - return Mono.just(result); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @SuppressWarnings("StringSplitter") - private static void addFunctionHelpers(Kernel kernel, Handlebars handlebars, - InvocationContext context) { - kernel - .getPlugins() - .forEach(plugin -> { - plugin - .iterator() - .forEachRemaining(kernelFunction -> { - String functionName = kernelFunction.getName(); - String pluginName = plugin.getName(); - handlebars.registerHelper( - ToolCallBehavior.formFullFunctionName(pluginName, functionName), - functionInvokeHelper(kernel, kernelFunction, context)); - }); - - }); - } - - private static Helper functionInvokeHelper( - Kernel kernel, - KernelFunction kernelFunction, - InvocationContext invocationContext) { - return (context, options) -> { - - KernelArguments.Builder builder = KernelArguments.builder(); - if (context instanceof KernelArguments) { - builder.withVariables((KernelArguments) context); - } else { - builder.withInput(context); - } - - if (options.hash(MAIN_KEY) != null) { - builder.withVariables(options.hash - .entrySet() - .stream() - .collect(Collectors.toMap( - Entry::getKey, - entry -> invocationContext - .getContextVariableTypes() - .contextVariableOf(entry.getValue())))); - } - - // TODO Figure out if possible to do async render - return kernelFunction - .invokeAsync(kernel) - .withArguments(builder.build()) - .block() - .getResult(); - }; - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateException.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateException.java deleted file mode 100644 index e0fe492c1..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateException.java +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.templateengine.semantickernel; - -import com.microsoft.semantickernel.exceptions.SKException; -import com.microsoft.semantickernel.localization.SemanticKernelResources; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Exception thrown when a template error occurs. - */ -public class TemplateException extends SKException { - - /** - * Error code. - */ - @Nonnull - private final ErrorCodes errorCode; - - /** - * Initializes a new instance of the {@code TemplateException} class with a provided error - * code. - * - * @param error The error code. - */ - public TemplateException(@Nonnull ErrorCodes error) { - this(error, null, null); - } - - /** - * Initializes a new instance of the {@code TemplateException} class with a provided error - * code. - * - * @param errorCode The error code. - * @param message The exception message. - */ - public TemplateException(@Nonnull ErrorCodes errorCode, @Nullable String message) { - this(errorCode, message, null); - } - - /** - * Initializes a new instance of the {@code TemplateException} class with a provided error - * code. - * - * @param errorCode The error code. - * @param message The exception message. - * @param innerException The exception that is the cause of the current exception. - */ - public TemplateException( - @Nonnull ErrorCodes errorCode, - @Nullable String message, - @Nullable Throwable innerException) { - super(formatDefaultMessage(errorCode.getMessage(), message), innerException); - this.errorCode = errorCode; - } - - // spotless:off - - /** - * Gets the error code for this exception. - * - * @return The error code. - */ - //spotless:on - public ErrorCodes getErrorCode() { - return errorCode; - } - - // spotless:off - - /** - * Error codes for {@code TemplateException}. - */ - //spotless:on - public enum ErrorCodes { - - // spotless:off - /** - * Unknown error. - */ - //spotless:on - UNKNOWN_ERROR(SemanticKernelResources.getString("unknown.error")), - - // spotless:off - /** - * Syntax error, the template syntax used is not valid. - */ - //spotless:on - SYNTAX_ERROR( - SemanticKernelResources - .getString("syntax.error.the.template.syntax.used.is.not.valid")), - - // spotless:off - /** - * The block type produced be the tokenizer was not expected. - */ - UNEXPECTED_BLOCK_TYPE(SemanticKernelResources.getString( - "the.block.type.produced.be.the.tokenizer.was.not.expected")), - - //spotless:off - /** - * The template requires an unknown function. - */ - //spotless:on - FUNCTION_NOT_FOUND( - SemanticKernelResources.getString("the.template.requires.an.unknown.function")), - - // spotless:off - /** - * The template execution failed, e.g. a function call threw an exception. - */ - //spotless:on - RUNTIME_ERROR(SemanticKernelResources.getString( - "the.template.execution.failed.e.g.a.function.call.threw.an.exception")); - - private final String message; - - ErrorCodes(String message) { - this.message = message; - } - - // spotless:off - - /** - * Gets the message for the error code. - * - * @return The error code message - */ - //spotless:on - public String getMessage() { - return message; - } - } -} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/text/TextChunker.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/text/TextChunker.java deleted file mode 100644 index 470a2deff..000000000 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/text/TextChunker.java +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.text; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Split text in chunks, attempting to leave meaning intact. For plain text, split looking at new - * lines first, then periods, and so on. For markdown, split looking at punctuation first, and so - * on. - */ -public class TextChunker { - - private static final String s_spaceChar = " "; - private static final List s_plaintextSplitOptions = Stream - .of("[\n\r]", "\\.", "[\\?\\!]", ";", ":", ",", "[\\)\\]\\}]", " ", "\\-", null) - .map(it -> it == null ? null : Pattern.compile(it, Pattern.MULTILINE)) - .collect(Collectors.toList()); - - private static final List s_markdownSplitOptions = Stream - .of("\\.", "[\\?\\!]", ";", ":", ",", "[\\)\\]\\}]", " ", "\\-", "[\n\r]", null) - .map(it -> it == null ? null : Pattern.compile(it, Pattern.MULTILINE)) - .collect(Collectors.toList()); - - /** - * Split plain text into lines - * - * @param text Text to split - * @param maxTokensPerLine Maximum number of tokens per line - * @return List of lines - */ - public static List splitPlainTextLines(String text, int maxTokensPerLine) { - return internalSplitLines(text, maxTokensPerLine, true, s_plaintextSplitOptions); - } - - /** - * Split markdown text into lines - * - * @param text Text to split - * @param maxTokensPerLine Maximum number of tokens per line - * @return List of lines - */ - public static List splitMarkDownLines(String text, int maxTokensPerLine) { - List result = new ArrayList<>(); - internalSplitLines(text, maxTokensPerLine, true, s_markdownSplitOptions); - return result; - } - - /** - * Split plain text into paragraphs - * - * @param lines Lines of text - * @param maxTokensPerParagraph Maximum number of tokens per paragraph. - * @return List of paragraphs - */ - public static List splitPlainTextParagraphs( - List lines, int maxTokensPerParagraph) { - return internalSplitTextParagraphs( - lines, - maxTokensPerParagraph, - (text) -> internalSplitLines( - text, maxTokensPerParagraph, false, s_plaintextSplitOptions)); - } - - /** - * Split markdown text into paragraphs - * - * @param lines Lines of text - * @param maxTokensPerParagraph Maximum number of tokens per paragraph - * @return List of paragraphs - */ - public static List splitMarkdownParagraphs( - List lines, int maxTokensPerParagraph) { - return internalSplitTextParagraphs( - lines, - maxTokensPerParagraph, - (text) -> internalSplitLines( - text, maxTokensPerParagraph, false, s_markdownSplitOptions)); - } - - private static List internalSplitTextParagraphs( - List lines, - int maxTokensPerParagraph, - Function> longLinesSplitter) { - if (lines.isEmpty()) { - return new ArrayList<>(); - } - - // Split long lines first - ArrayList truncatedLines = new ArrayList<>(); - for (String line : lines) { - truncatedLines.addAll(longLinesSplitter.apply(line)); - } - - lines = truncatedLines; - - // Group lines in paragraphs - List paragraphs = new ArrayList<>(); - StringBuilder currentParagraph = new StringBuilder(); - - for (String line : lines) { - // "+1" to account for the "new line" added by AppendLine() - if (currentParagraph.length() > 0 - && TokenCount(currentParagraph.length()) + TokenCount(line.length()) - + 1 >= maxTokensPerParagraph) { - paragraphs.add(currentParagraph.toString().trim()); - currentParagraph = new StringBuilder(); - } - - currentParagraph.append(line).append("\n"); - } - - if (currentParagraph.length() > 0) { - paragraphs.add(currentParagraph.toString().trim()); - } - - // distribute text more evenly in the last paragraphs when the last paragraph is too short. - if (paragraphs.size() > 1) { - String lastParagraph = paragraphs.get(paragraphs.size() - 1); - String secondLastParagraph = paragraphs.get(paragraphs.size() - 2); - - if (TokenCount(lastParagraph.length()) < maxTokensPerParagraph / 4) { - List lastParagraphTokens = Arrays.stream(lastParagraph.split(s_spaceChar)) - .filter(it -> !it.isEmpty()) - .collect(Collectors.toList()); - List secondLastParagraphTokens = Arrays - .stream(secondLastParagraph.split(s_spaceChar)) - .filter(it -> !it.isEmpty()) - .collect(Collectors.toList()); - - int lastParagraphTokensCount = lastParagraphTokens.size(); - int secondLastParagraphTokensCount = secondLastParagraphTokens.size(); - - if (lastParagraphTokensCount - + secondLastParagraphTokensCount <= maxTokensPerParagraph) { - StringBuilder newSecondLastParagraph = new StringBuilder(); - for (int i = 0; i < secondLastParagraphTokensCount; i++) { - if (newSecondLastParagraph.length() != 0) { - newSecondLastParagraph.append(' '); - } - - newSecondLastParagraph.append(secondLastParagraphTokens.get(i)); - } - - for (int i = 0; i < lastParagraphTokensCount; i++) { - if (newSecondLastParagraph.length() != 0) { - newSecondLastParagraph.append(' '); - } - - newSecondLastParagraph.append(lastParagraphTokens.get(i)); - } - - paragraphs.set(paragraphs.size() - 2, newSecondLastParagraph.toString().trim()); - paragraphs.remove(paragraphs.size() - 1); - } - } - } - - return paragraphs; - } - - private static List internalSplitLines( - String text, int maxTokensPerLine, boolean trim, List splitOptions) { - text = text.replaceAll("\\r?\\n|\\r", "\n"); - - SplitString result = split(text, maxTokensPerLine, - Collections.singletonList(splitOptions.get(0)), trim); - if (result.inputWasSplit) { - for (int i = 1; i < splitOptions.size(); i++) { - result = split( - result.result, - maxTokensPerLine, - Collections.singletonList(splitOptions.get(i)), - trim); - - if (!result.inputWasSplit) { - break; - } - } - } - return result.result; - } - - private static SplitString split( - List input, int maxTokens, List separators, boolean trim) { - List result = new ArrayList<>(); - boolean modified = false; - for (String str : input) { - SplitString r = split(str, maxTokens, separators, trim); - result.addAll(r.result); - - modified |= r.inputWasSplit; - } - return new SplitString(modified, result); - } - - private static int indexOfAny(List separators, String input) { - return separators.stream() - .map( - it -> { - Matcher matcher = it.matcher(input); - if (matcher.find()) { - return matcher.start(); - } else { - return -1; - } - }) - .filter(it -> it != -1) - .min(Integer::compareTo) - .orElse(-1); - } - - private static SplitString split( - String input, int maxTokens, List separators, boolean trim) { - // Debug.Assert(inputString is null || input.SequenceEqual(inputString.AsSpan())); - boolean inputWasSplit; - if (TokenCount(input.length()) > maxTokens) { - - inputWasSplit = true; - - int half = input.length() / 2; - int cutPoint = -1; - - if (separators.size() == 1 && separators.get(0) == null) { - cutPoint = half; - } else if (input.length() > 2) { - int pos = 0; - while (true) { - int index = indexOfAny(separators, input.substring(pos, input.length() - 1)); - if (index < 0) { - break; - } - - index += pos; - - if (Math.abs(half - index) < Math.abs(half - cutPoint)) { - cutPoint = index + 1; - } - - pos = index + 1; - } - } - - List result = Collections.singletonList(input); - - if (cutPoint > 0) { - String firstHalf = input.substring(0, cutPoint); - String secondHalf = input.substring(cutPoint); - if (trim) { - firstHalf = firstHalf.trim(); - secondHalf = secondHalf.trim(); - } - - // Recursion - SplitString first = split(firstHalf, maxTokens, separators, trim); - SplitString second = split(secondHalf, maxTokens, separators, trim); - - result = Stream.concat(first.result.stream(), second.result.stream()) - .collect(Collectors.toList()); - inputWasSplit = first.inputWasSplit || second.inputWasSplit; - } - - return new SplitString(inputWasSplit, result); - } - - return new SplitString(false, Collections.singletonList(input)); - } - - private static int TokenCount(int inputLength) { - // TODO: partitioning methods should be configurable to allow for different tokenization - // strategies - // depending on the model to be called. For now, we use an extremely rough estimate. - return inputLength / 4; - } - - private static class SplitString { - - public final boolean inputWasSplit; - public final List result; - - private SplitString(boolean inputWasSplit, List result) { - this.inputWasSplit = inputWasSplit; - this.result = result; - } - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableTypeConverterTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableTypeConverterTest.java deleted file mode 100644 index 2fdb2bfbe..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/ContextVariableTypeConverterTest.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import java.io.Serializable; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.stream.Stream; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestFactory; - -public class ContextVariableTypeConverterTest { - - @TestFactory - public Stream testConvertIntegerToString() { - return Stream.of( - new TestCase<>("StringToInteger", String.class, Integer.class, "1"), - new TestCase<>("IntegerToString", Integer.class, String.class, 1), - - new TestCase<>("StringToFloat", String.class, Float.class, "0.1"), - new TestCase<>("FloatToString", Float.class, String.class, 0.1f), - - new TestCase<>("StringToBoolean", String.class, Boolean.class, "true"), - new TestCase<>("BooleanToString", Boolean.class, String.class, true), - - new TestCase<>("NumberToInteger", Number.class, Integer.class, 100.0f), - new TestCase<>("IntegerToNumber", Integer.class, Number.class, 100), - - new TestCase<>("StringToDate", String.class, OffsetDateTime.class, - ZonedDateTime.now(ZoneId.systemDefault()).format(DateTimeFormatter.ISO_DATE_TIME)), - new TestCase<>("DateToString", OffsetDateTime.class, String.class, - OffsetDateTime.now(ZoneId.systemDefault()))) - .map(s -> DynamicTest.dynamicTest(s.name, () -> { - Assertions.assertNotNull(ContextVariable.ofGlobalType(s.object)); - Assertions.assertNotNull(ContextVariable.ofGlobalType(s.object).getValue()); - - try { - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass( - s.targetClazz); - Assertions.assertNotNull(ContextVariable.convert(s.object, type)); - } catch (Exception ignored) { - - } - })); - } - - class NoToString { - - } - - class WithToString { - - @Override - public String toString() { - return "foo"; - } - } - - @Test - public void checkStringConversionIgnoresObjectReferences() { - Assertions.assertNull(StringVariableContextVariableTypeConverter.convertToString(null)); - Assertions.assertNull( - StringVariableContextVariableTypeConverter.convertToString(new NoToString())); - Assertions.assertEquals("foo", - StringVariableContextVariableTypeConverter.convertToString(new WithToString())); - } - - private static class TestCase { - - private final String name; - private final Class clazz; - private final Class targetClazz; - private final T object; - - private TestCase(String name, Class clazz, Class targetClazz, T object) { - this.name = name; - this.clazz = clazz; - this.targetClazz = targetClazz; - this.object = object; - } - } - -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverterTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverterTest.java deleted file mode 100644 index fc7f5033e..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/contextvariables/converters/NumberVariableContextVariableTypeConverterTest.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.contextvariables.converters; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableType; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import org.junit.jupiter.api.Test; - -public class NumberVariableContextVariableTypeConverterTest { - - /** - * Test of toObject method, of class NumberVariableContextVariableTypeConverter. - */ - @Test - void testConvertIntegerToString() { - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - Object expResult = "1"; - Object result = instance.toObject(new ContextVariableTypes(), 1, String.class); - assertEquals(expResult, result); - } - - /** - * Test of fromObject method, of class NumberVariableContextVariableTypeConverter. - */ - @Test - void testFromStringToInteger() { - Object s = "123"; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - Number expResult = Integer.valueOf((String) s); - Number result = instance.fromObject(s); - assertEquals(expResult, result); - } - - @Test - void testFromPromptStringToInteger() { - String s = "123"; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - Number expResult = Integer.valueOf(s); - Number result = instance.fromPromptString(s); - assertEquals(expResult, result); - } - - @Test - void testFromPromptStringReturnsNullForEmptyString() { - String s = ""; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - Number expResult = null; - Number result = instance.fromPromptString(s); - assertEquals(expResult, result); - } - - @Test - void testFromPromptStringReturnsNullForNullString() { - String s = null; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - Number expResult = null; - Number result = instance.fromPromptString(s); - assertEquals(expResult, result); - } - - @Test - void testToPromptString() { - Integer num = 123; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - String expResult = "123"; - String result = instance.toPromptString(new ContextVariableTypes(), num); - assertEquals(expResult, result); - } - - @Test - void testToPromptStringReturnsEmptyStringForNull() { - Integer num = null; - ContextVariableType type = ContextVariableTypes - .getGlobalVariableTypeForClass(Integer.class); - ContextVariableTypeConverter instance = type.getConverter(); - String expResult = ""; - String result = instance.toPromptString(new ContextVariableTypes(), num); - assertEquals(expResult, result); - } - - @Test - void testFromStringToDouble() { - Object s = "12.0"; - double expResult = 12.0d; - ContextVariable result = ContextVariable.convert(s, double.class, null); - assertEquals(expResult, result.getValue()); - } -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/Hotel.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/Hotel.java deleted file mode 100644 index f6741e5a5..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/Hotel.java +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey; -import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; - -import java.util.List; - -public class Hotel { - @VectorStoreRecordKey - private final String id; - - @VectorStoreRecordData(isFilterable = true) - private final String name; - - @VectorStoreRecordData - private final int code; - - @JsonProperty("summary") - @VectorStoreRecordData() - private final String description; - - @JsonProperty("summaryEmbedding1") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.EUCLIDEAN_DISTANCE) - private final List euclidean; - - @JsonProperty("summaryEmbedding2") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_DISTANCE) - private final List cosineDistance; - - @JsonProperty("summaryEmbedding3") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.COSINE_SIMILARITY) - private final List cosineSimilarity; - - @JsonProperty("summaryEmbedding4") - @VectorStoreRecordVector(dimensions = 8, distanceFunction = DistanceFunction.DOT_PRODUCT) - private final List dotProduct; - @VectorStoreRecordData - private double rating; - - public Hotel() { - this(null, null, 0, null, null, null, null, null, 0.0); - } - - @JsonCreator - public Hotel( - @JsonProperty("id") String id, - @JsonProperty("name") String name, - @JsonProperty("code") int code, - @JsonProperty("summary") String description, - @JsonProperty("summaryEmbedding1") List euclidean, - @JsonProperty("summaryEmbedding2") List cosineDistance, - @JsonProperty("summaryEmbedding2") List cosineSimilarity, - @JsonProperty("summaryEmbedding3") List dotProduct, - @JsonProperty("rating") double rating) { - this.id = id; - this.name = name; - this.code = code; - this.description = description; - this.euclidean = euclidean; - this.cosineDistance = euclidean; - this.cosineSimilarity = euclidean; - this.dotProduct = euclidean; - this.rating = rating; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public int getCode() { - return code; - } - - public String getDescription() { - return description; - } - - public List getEuclidean() { - return euclidean; - } - - public List getCosineDistance() { - return cosineDistance; - } - - public List getDotProduct() { - return dotProduct; - } - - public double getRating() { - return rating; - } - - public void setRating(double rating) { - this.rating = rating; - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionTest.java deleted file mode 100644 index bd2c633d6..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreRecordCollectionTest.java +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; -import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; -import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; -import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; - -public class VolatileVectorStoreRecordCollectionTest { - - private static VolatileVectorStoreRecordCollection recordCollection; - - @BeforeAll - public static void setup() { - recordCollection = new VolatileVectorStoreRecordCollection<>( - "hotels", - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); - recordCollection.createCollectionIfNotExistsAsync().block(); - } - - @BeforeEach - public void clearCollection() { - recordCollection.deleteCollectionAsync().block(); - recordCollection.createCollectionAsync().block(); - } - - private static List getHotels() { - return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", - Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f), null, null, null, - 4.0), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", - Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f), null, null, null, - 4.0), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", - Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f), null, null, null, - 5.0), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", - Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f), null, null, null, - 4.0), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", - Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f), null, null, null, - 4.0)); - } - - /** - * Search embeddings similar to the third hotel embeddings. - * In order of similarity: - * 1. Hotel 3 - * 2. Hotel 1 - * 3. Hotel 4 - */ - private static final List SEARCH_EMBEDDINGS = Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, - -0.8f, 1.1f, -2.2f, 8.2f); - - @Test - public void createAndDeleteCollectionAsync() { - assertEquals(true, recordCollection.collectionExistsAsync().block()); - - recordCollection.deleteCollectionAsync().block(); - assertEquals(false, recordCollection.collectionExistsAsync().block()); - - recordCollection.createCollectionAsync().block(); - assertEquals(true, recordCollection.collectionExistsAsync().block()); - } - - @Test - public void upsertRecordAsync() { - List hotels = getHotels(); - for (Hotel hotel : hotels) { - recordCollection.upsertAsync(hotel, null).block(); - } - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getName(), retrievedHotel.getName()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @Test - public void upsertBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - Hotel retrievedHotel = recordCollection.getAsync(hotel.getId(), null).block(); - assertNotNull(retrievedHotel); - assertEquals(hotel.getId(), retrievedHotel.getId()); - assertEquals(hotel.getName(), retrievedHotel.getName()); - assertEquals(hotel.getDescription(), retrievedHotel.getDescription()); - } - } - - @Test - public void getBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = hotels.stream().map(Hotel::getId).collect(Collectors.toList()); - List retrievedHotels = recordCollection.getBatchAsync(keys, null).block(); - - assertNotNull(retrievedHotels); - assertEquals(keys.size(), retrievedHotels.size()); - for (Hotel hotel : retrievedHotels) { - assertTrue(keys.contains(hotel.getId())); - } - } - - @Test - public void deleteRecordAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - for (Hotel hotel : hotels) { - recordCollection.deleteAsync(hotel.getId(), null).block(); - assertNull(recordCollection.getAsync(hotel.getId(), null).block()); - } - } - - @Test - public void deleteBatchAsync() { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - List keys = hotels.stream().map(Hotel::getId).collect(Collectors.toList()); - recordCollection.deleteBatchAsync(keys, null).block(); - - for (String key : keys) { - assertNull(recordCollection.getAsync(key, null).block()); - } - } - - @ParameterizedTest - @EnumSource(DistanceFunction.class) - public void exactSearch(DistanceFunction distanceFunction) { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withTop(3) - .build(); - - // Embeddings similar to the third hotel - List> results = recordCollection - .searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The third hotel should be the most similar - assertEquals(hotels.get(2).getId(), results.get(0).getRecord().getId()); - - options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withSkip(1) - .withTop(-100) - .build(); - - // Skip the first result - results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(1, results.size()); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId()); - } - - @ParameterizedTest - @EnumSource(DistanceFunction.class) - public void searchWithFilter(DistanceFunction distanceFunction) { - List hotels = getHotels(); - recordCollection.upsertBatchAsync(hotels, null).block(); - - VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(distanceFunction.getValue()) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); - - // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned - List> results = recordCollection - .searchAsync(SEARCH_EMBEDDINGS, options).block().getResults(); - assertNotNull(results); - assertEquals(3, results.size()); - // The first hotel should be the most similar - assertEquals(hotels.get(0).getId(), results.get(0).getRecord().getId()); - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreTest.java deleted file mode 100644 index 4cee074dc..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/data/VolatileVectorStoreTest.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.data; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class VolatileVectorStoreTest { - - private static VolatileVectorStore vectorStore; - - @BeforeAll - public static void setup() { - vectorStore = new VolatileVectorStore(); - } - - @Test - public void collectionNamesAsync() { - List collectionNames = Arrays.asList("hotels1", "hotels2", "hotels3"); - - for (String collectionName : collectionNames) { - vectorStore.getCollection(collectionName, - VolatileVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()) - .createCollectionAsync() - .block(); - } - - List retrievedCollectionNames = vectorStore.getCollectionNamesAsync().block(); - assertNotNull(retrievedCollectionNames); - assertEquals(collectionNames.size(), retrievedCollectionNames.size()); - for (String collectionName : collectionNames) { - assertTrue(retrievedCollectionNames.contains(collectionName)); - } - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoaderTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoaderTest.java deleted file mode 100644 index 5449814f9..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/implementation/EmbeddedResourceLoaderTest.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.implementation; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.CALLS_REAL_METHODS; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; - -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -public class EmbeddedResourceLoaderTest { - - @Test - public void testReadFile_Classpath() { - assertThrows(FileNotFoundException.class, () -> { - EmbeddedResourceLoader.readFile("nonexistent.txt", this.getClass()); - }); - } - - @Test - public void testReadFile_ClasspathRoot() { - assertThrows(FileNotFoundException.class, () -> { - EmbeddedResourceLoader.readFile("nonexistent.txt", this.getClass(), - EmbeddedResourceLoader.ResourceLocation.CLASSPATH_ROOT); - }); - } - - @Test - public void testReadFile_FileSystem() { - assertThrows(FileNotFoundException.class, () -> { - EmbeddedResourceLoader.readFile("nonexistent.txt", this.getClass(), - EmbeddedResourceLoader.ResourceLocation.FILESYSTEM); - }); - } - - @Test - public void testReadFile_Classpath_ExistingFile() throws FileNotFoundException { - try (MockedStatic mocked = Mockito.mockStatic( - EmbeddedResourceLoader.class, - withSettings().defaultAnswer(CALLS_REAL_METHODS))) { - - mocked - .when(() -> EmbeddedResourceLoader.getResourceAsStream(any(String.class), - any(Class.class))) - .thenReturn("file content"); - - String result = EmbeddedResourceLoader.readFile("existent.txt", - EmbeddedResourceLoaderTest.class); - assertEquals("file content", result); - } - } - - @Test - public void testReadFile_ClasspathRoot_ExistingFile() throws FileNotFoundException { - ClassLoader mockClassLoader = Mockito.mock(ClassLoader.class); - - InputStream inputStream = new ByteArrayInputStream( - "file content".getBytes(StandardCharsets.UTF_8)); - when(mockClassLoader.getResourceAsStream(any(String.class))).thenReturn(inputStream); - - Thread.currentThread().setContextClassLoader(mockClassLoader); - - String result = EmbeddedResourceLoader.readFile("existent.txt", - EmbeddedResourceLoaderTest.class, - EmbeddedResourceLoader.ResourceLocation.CLASSPATH_ROOT); - assertEquals("file content", result); - } - - @Test - public void testReadFile_FileSystem_ExistingFile() throws IOException { - try (MockedStatic mocked = Mockito.mockStatic( - EmbeddedResourceLoader.class, - withSettings().defaultAnswer(CALLS_REAL_METHODS))) { - - mocked.when(() -> EmbeddedResourceLoader.readFileFromFileSystem(any(String.class))) - .thenReturn("file content"); - - String result = EmbeddedResourceLoader.readFile("existent.txt", - EmbeddedResourceLoaderTest.class, - EmbeddedResourceLoader.ResourceLocation.FILESYSTEM); - assertEquals("file content", result); - } - } -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/localization/SemanticKernelResourcesTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/localization/SemanticKernelResourcesTest.java deleted file mode 100644 index 9158255f7..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/localization/SemanticKernelResourcesTest.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.localization; - -import java.util.Locale; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class SemanticKernelResourcesTest { - - @Test - public void languageAndCountry() { - SemanticKernelResources.setLocale(new Locale("en", "GB")); - - String result = SemanticKernelResources.localize("test_language_country", "a test string"); - - Assertions.assertEquals("GB english test value", result); - } - - @Test - public void valueAtTheLanguageLevel() { - SemanticKernelResources.setLocale(new Locale("en", "GB")); - - String result = SemanticKernelResources.localize("test_language", "a test string"); - - Assertions.assertEquals("English test value", result); - } - - @Test - public void topLevelValue() { - SemanticKernelResources.setLocale(new Locale("en", "GB")); - - String result = SemanticKernelResources.localize("test_top", "default value"); - - Assertions.assertEquals("Top level value", result); - } - - @Test - public void defaultValue() { - SemanticKernelResources.setLocale(new Locale("en", "GB")); - - String result = SemanticKernelResources.localize("not-there", "default value"); - - Assertions.assertEquals("default value", result); - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettingsTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettingsTest.java deleted file mode 100644 index 9c21b1158..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettingsTest.java +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.orchestration; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.orchestration.responseformat.ResponseFormat.Type; -import org.junit.jupiter.api.Test; - -public class PromptExecutionSettingsTest { - - @Test - public void testDefaultValues() { - PromptExecutionSettings settings = new PromptExecutionSettings.Builder().build(); - - assertEquals(PromptExecutionSettings.DEFAULT_SERVICE_ID, settings.getServiceId()); - assertEquals(PromptExecutionSettings.DEFAULT_MAX_TOKENS, settings.getMaxTokens()); - assertEquals(PromptExecutionSettings.DEFAULT_TEMPERATURE, settings.getTemperature()); - assertEquals(PromptExecutionSettings.DEFAULT_TOP_P, settings.getTopP()); - assertEquals(PromptExecutionSettings.DEFAULT_PRESENCE_PENALTY, - settings.getPresencePenalty()); - assertEquals(PromptExecutionSettings.DEFAULT_FREQUENCY_PENALTY, - settings.getFrequencyPenalty()); - assertEquals(PromptExecutionSettings.DEFAULT_BEST_OF, settings.getBestOf()); - assertEquals(PromptExecutionSettings.DEFAULT_RESULTS_PER_PROMPT, - settings.getResultsPerPrompt()); - assertEquals("", settings.getModelId()); - assertEquals("", settings.getUser()); - assertTrue(settings.getStopSequences().isEmpty()); - assertTrue(settings.getTokenSelectionBiases().isEmpty()); - } - - @Test - public void testCustomValues() { - String serviceId = "custom-service"; - int maxTokens = 512; - double temperature = 0.8; - double topP = 0.5; - double presencePenalty = 0.2; - double frequencyPenalty = 0.3; - int bestOf = 3; - int resultsPerPrompt = 5; - String modelId = "custom-model"; - String user = "custom-user"; - - PromptExecutionSettings settings = new PromptExecutionSettings.Builder() - .withServiceId(serviceId) - .withMaxTokens(maxTokens) - .withTemperature(temperature) - .withTopP(topP) - .withPresencePenalty(presencePenalty) - .withFrequencyPenalty(frequencyPenalty) - .withBestOf(bestOf) - .withResultsPerPrompt(resultsPerPrompt) - .withModelId(modelId) - .withUser(user) - .build(); - - assertEquals(serviceId, settings.getServiceId()); - assertEquals(maxTokens, settings.getMaxTokens()); - assertEquals(temperature, settings.getTemperature()); - assertEquals(topP, settings.getTopP()); - assertEquals(presencePenalty, settings.getPresencePenalty()); - assertEquals(frequencyPenalty, settings.getFrequencyPenalty()); - assertEquals(bestOf, settings.getBestOf()); - assertEquals(resultsPerPrompt, settings.getResultsPerPrompt()); - assertEquals(modelId, settings.getModelId()); - assertEquals(user, settings.getUser()); - assertTrue(settings.getStopSequences().isEmpty()); - assertTrue(settings.getTokenSelectionBiases().isEmpty()); - } - - @Test - void testJsonDeserialize() throws Exception { - String json = "{" - + "\"service_id\":\"custom-service\"," - + "\"max_tokens\":512," - + "\"temperature\":0.8," - + "\"top_p\":0.5," - + "\"presence_penalty\":0.2," - + "\"frequency_penalty\":0.3," - + "\"best_of\":3," - + "\"results_per_prompt\":5," - + "\"model_id\":\"custom-model\"," - + "\"user\":\"custom-user\"" - + "}"; - PromptExecutionSettings settings = new ObjectMapper().readValue(json, - PromptExecutionSettings.class); - - assertEquals("custom-service", settings.getServiceId()); - assertEquals(512, settings.getMaxTokens()); - assertEquals(0.8, settings.getTemperature()); - assertEquals(0.5, settings.getTopP()); - assertEquals(0.2, settings.getPresencePenalty()); - assertEquals(0.3, settings.getFrequencyPenalty()); - assertEquals(3, settings.getBestOf()); - assertEquals(5, settings.getResultsPerPrompt()); - assertEquals("custom-model", settings.getModelId()); - assertEquals("custom-user", settings.getUser()); - assertTrue(settings.getStopSequences().isEmpty()); - assertTrue(settings.getTokenSelectionBiases().isEmpty()); - } - - @Test - void testJsonDeserializeAndBuilder() throws Exception { - String json = "{" - + "\"service_id\":\"custom-service\"," - + "\"max_tokens\":512," - + "\"temperature\":0.8," - + "\"top_p\":0.5," - + "\"presence_penalty\":0.2," - + "\"frequency_penalty\":0.3," - + "\"best_of\":3," - + "\"results_per_prompt\":5," - + "\"model_id\":\"custom-model\"," - + "\"user\":\"custom-user\"," - + "\"response_format\" : {\"type\" : \"text\"}" - + "}"; - PromptExecutionSettings settingsFromJson = new ObjectMapper().readValue(json, - PromptExecutionSettings.class); - - PromptExecutionSettings settingsFromBuilder = PromptExecutionSettings.builder() - .withServiceId("custom-service") - .withMaxTokens(512) - .withTemperature(0.8) - .withTopP(0.5) - .withPresencePenalty(0.2) - .withFrequencyPenalty(0.3) - .withBestOf(3) - .withResultsPerPrompt(5) - .withModelId("custom-model") - .withUser("custom-user") - .withResponseFormat(Type.TEXT) - .build(); - - assertEquals( - new ObjectMapper().writerWithDefaultPrettyPrinter() - .writeValueAsString(settingsFromBuilder), - new ObjectMapper().writerWithDefaultPrettyPrinter() - .writeValueAsString(settingsFromJson)); - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/plugin/KernelPluginFactoryTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/plugin/KernelPluginFactoryTest.java deleted file mode 100644 index 1203d01f2..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/plugin/KernelPluginFactoryTest.java +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.plugin; - -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.nio.file.Paths; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -public class KernelPluginFactoryTest { - - public static class TestPlugin { - - @DefineKernelFunction - public String testFunction( - @KernelFunctionParameter(name = "input") String input) { - return "test" + input; - } - - @DefineKernelFunction(returnType = "int") - public Mono asyncTestFunction( - @KernelFunctionParameter(name = "input") String input) { - return Mono.just(1); - } - } - - @Test - public void createFromObjectTest() { - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new TestPlugin(), - "test"); - - Assertions.assertNotNull(plugin); - Assertions.assertEquals(plugin.getName(), "test"); - Assertions.assertEquals(plugin.getFunctions().size(), 2); - - KernelFunction testFunction = plugin.getFunctions() - .get("testFunction"); - - Assertions.assertNotNull(testFunction); - Assertions.assertNotNull(testFunction.getMetadata().getOutputVariableType()); - Assertions.assertEquals(testFunction.getMetadata().getOutputVariableType().getType(), - String.class); - Assertions.assertEquals(testFunction.getMetadata().getParameters().size(), 1); - Assertions.assertEquals(testFunction.getMetadata().getParameters().get(0).getType(), - String.class.getName()); - - } - - @Test - public void importPluginFromDirectoryTest() { - KernelPlugin plugin = KernelPluginFactory.importPluginFromDirectory( - Paths.get("./src/test/resources/Plugins"), - "ExamplePlugins", - null); - - Assertions.assertNotNull(plugin); - Assertions.assertEquals(plugin.getName(), "ExamplePlugins"); - Assertions.assertEquals(plugin.getFunctions().size(), 1); - - KernelFunction testFunction = plugin.getFunctions() - .get("examplefunction"); - - Assertions.assertNotNull(testFunction); - Assertions.assertNotNull(testFunction.getMetadata().getOutputVariableType()); - Assertions.assertEquals(testFunction.getMetadata().getOutputVariableType().getType(), - String.class); - Assertions.assertEquals(testFunction.getMetadata().getParameters().size(), 1); - Assertions.assertEquals(testFunction.getMetadata().getParameters().get(0).getTypeClass(), - String.class); - - } - - @Test - public void importPluginFromResourcesDirectoryTest() { - KernelPlugin plugin = KernelPluginFactory.importPluginFromResourcesDirectory( - "src/test/resources/Plugins", - "ExamplePlugins", - "ExampleFunction", - null); - - Assertions.assertNotNull(plugin); - Assertions.assertEquals(plugin.getName(), "ExamplePlugins"); - Assertions.assertEquals(plugin.getFunctions().size(), 1); - - KernelFunction testFunction = plugin.getFunctions() - .get("examplefunction"); - - Assertions.assertNotNull(testFunction); - Assertions.assertNotNull(testFunction.getMetadata().getOutputVariableType()); - Assertions.assertEquals(testFunction.getMetadata().getOutputVariableType().getType(), - String.class); - Assertions.assertEquals(testFunction.getMetadata().getParameters().size(), 1); - Assertions.assertEquals(testFunction.getMetadata().getParameters().get(0).getTypeClass(), - String.class); - - } - -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethodTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethodTest.java deleted file mode 100644 index a2dae1370..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromMethodTest.java +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestFactory; -import reactor.core.publisher.Mono; - -public class KernelFunctionFromMethodTest { - - public KernelFunctionFromMethodTest() { - } - - public static class ExamplePlugin { - - @DefineKernelFunction(name = "sqrt", description = "Take the square root of a number") - public static double sqrt( - @KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) { - return Math.sqrt(number1); - } - } - - @Test - void typeConversionOnMethodCall() { - KernelPlugin plugin = KernelPluginFactory.createFromObject( - new ExamplePlugin(), "ExamplePlugin"); - - Kernel kernel = Kernel.builder().build(); - - FunctionResult result = plugin - .get("sqrt") - .invokeAsync(kernel) - .withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class)) - .withArguments( - KernelArguments.builder() - .withVariable("number1", "12.0") - .build()) - .block(); - - Assertions.assertEquals("3.4641016151377544", result.getResult()); - } - - @Test - void testCreate() throws Exception { - Method method = String.class.getMethod("concat", String.class); - String pluginName = "test-plugin"; - String functionName = "concat"; - String description = "concatenate two strings"; - List parameters = Collections.singletonList(InputVariable.build( - "string1", String.class, "first string to concatenate", null, null, true)); - OutputVariable returnParameter = new OutputVariable<>( - "concatenated strings", String.class); - KernelFunction result = KernelFunctionFromMethod.create(method, "test", pluginName, - functionName, description, parameters, returnParameter); - assertEquals(functionName, result.getName()); - assertEquals(pluginName, result.getPluginName()); - assertEquals(description, result.getDescription()); - assertEquals(parameters, result.getMetadata().getParameters()); - assertEquals(returnParameter, result.getMetadata().getOutputVariableType()); - } - - /** - * Test of builder method, of class KernelFunctionFromMethod. - */ - @Test - void testBuilder() { - String pluginName = null; - String functionName = "concat"; - String description = "concatenate two strings"; - List parameters = Collections - .singletonList(new InputVariable("string1", - "java.lang.String", "first string to concatenate", null, true, null)); - OutputVariable returnParameter = new OutputVariable<>("java.lang.String", - "concatenated strings"); - KernelFunction result = new KernelFunctionFromPrompt.Builder() - .withName(functionName) - .withDescription(description) - .withInputParameters(parameters) - .withOutputVariable(returnParameter) - .withPromptTemplate((kernel, args, context) -> Mono.empty()) - .build(); - assertEquals(functionName, result.getName()); - assertEquals(pluginName, result.getPluginName()); - assertEquals(description, result.getDescription()); - // TODO: This assert fails because getParameters is a List>, not an List - // This feels like it's broken. Until this is fixed, we can compare the types - // assertEquals(parameters, result.getMetadata().getParameters()); - assertEquals(parameters.size(), result.getMetadata().getParameters().size()); - for (int i = 0; i < parameters.size(); i++) { - assertEquals(parameters.get(i).getDescription(), - result.getMetadata().getParameters().get(i).getDescription()); - assertEquals(parameters.get(i).getName(), - result.getMetadata().getParameters().get(i).getName()); - assertEquals(parameters.get(i).getType(), - result.getMetadata().getParameters().get(i).getType()); - assertEquals(parameters.get(i).isRequired(), - result.getMetadata().getParameters().get(i).isRequired()); - } - assertEquals(returnParameter, result.getMetadata().getOutputVariableType()); - assertEquals(returnParameter.getType(), - result.getMetadata().getOutputVariableType().getType()); - assertEquals(returnParameter.getDescription(), - result.getMetadata().getOutputVariableType().getDescription()); - } - - /** - * Test of invokeAsync method, of class KernelFunctionFromMethod. - */ - @Test - @Disabled("TODO: needs mocked http server") - void testInvokeAsync() { - } - - @TestFactory - public Stream runInvocationConversionTests() { - return Arrays.asList( - new NoAnnotation(), - new NoTypeOnAnnotation(), - new PrimitiveTypeOnAnnotation(), - new SuperClassTypeTypeOnAnnotation(), - new DefaultTypeOnAnnotation(), - new StringTargetTypeOnAnnotation(), - new ConvertUsingTargetType()) - .stream() - .map( - testClazz -> DynamicTest - .dynamicTest( - testClazz.getClass().getName() + "Test", - () -> { - - ContextVariableTypeConverter targetConverter = ContextVariableTypeConverter - .builder(TargetClass.class) - .fromObject(i -> { - if (i instanceof SourceClass) { - return new TargetClass(((SourceClass) i).value); - } - return (TargetClass) i; - }) - .toPromptString(i -> null) - .build(); - - Boolean result = (Boolean) KernelFunctionFromMethod.createFromMethod( - testClazz.getMethod(), - testClazz) - .build() - .invoke( - Kernel.builder().build(), - testClazz.getArguments(), - null, - InvocationContext.builder() - .withContextVariableConverter(targetConverter) - .build()) - .getResult(); - - Assertions.assertTrue(result); - - testClazz.assertCalled(); - })); - } - - interface InvocationTest { - - Method getMethod() throws NoSuchMethodException; - - KernelArguments getArguments(); - - void assertCalled(); - } - - @Nested - class NoAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method(Integer i) { - called = i == 123; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", Integer.class); - } - - @Override - public KernelArguments getArguments() { - return KernelArguments.builder() - .withVariable("i", 123) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - @Nested - class NoTypeOnAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i") Integer i) { - called = i == 123; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", Integer.class); - } - - @Override - public KernelArguments getArguments() { - return KernelArguments.builder() - .withVariable("i", 123) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - @Nested - class PrimitiveTypeOnAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i", type = int.class) int i) { - called = i == 123; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", int.class); - } - - @Override - public KernelArguments getArguments() { - return KernelArguments.builder() - .withVariable("i", 123) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - @Nested - class SuperClassTypeTypeOnAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i", type = List.class) List i) { - called = i.size() == 3; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", List.class); - } - - @Override - public KernelArguments getArguments() { - return KernelArguments.builder() - .withVariable("i", Arrays.asList(1, 2, 3)) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - @Nested - class DefaultTypeOnAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i", type = int.class, defaultValue = "123") int i) { - called = i == 123; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", int.class); - } - - @Override - public KernelArguments getArguments() { - return KernelArguments.builder() - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - @Nested - class StringTargetTypeOnAnnotation implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i", type = String.class) String i) { - called = i.equals("123"); - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", String.class); - } - - @Override - public KernelArguments getArguments() { - - ContextVariableTypeConverter dbConverter = ContextVariableTypeConverter - .builder(BigDecimal.class) - .fromObject(i -> (BigDecimal) i) - .toPromptString(i -> null) - .build(); - - return KernelArguments.builder() - .withVariable("i", new BigDecimal(123), dbConverter) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - - class TargetClass { - - final int value; - - TargetClass(int value) { - this.value = value; - } - } - - class SourceClass { - - final int value; - - SourceClass(int value) { - this.value = value; - } - } - - @Nested - class ConvertUsingTargetType implements InvocationTest { - - boolean called = false; - - @DefineKernelFunction - public boolean method( - @KernelFunctionParameter(name = "i", type = TargetClass.class) TargetClass i) { - called = i.value == 123; - return called; - } - - public Method getMethod() throws NoSuchMethodException { - return this.getClass().getMethod("method", TargetClass.class); - } - - @Override - public KernelArguments getArguments() { - - ContextVariableTypeConverter sourceConverter = ContextVariableTypeConverter - .builder(SourceClass.class) - .fromObject(i -> (SourceClass) i) - .toPromptString(i -> null) - .build(); - return KernelArguments.builder() - .withVariable("i", new SourceClass(123), sourceConverter) - .build(); - } - - @Override - public void assertCalled() { - Assertions.assertTrue(called); - } - } - -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYamlTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYamlTest.java deleted file mode 100644 index eb71ffec7..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionYamlTest.java +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.fail; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.HashMap; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -@SuppressWarnings("DoubleBraceInitialization") -public class KernelFunctionYamlTest { - - @Test - public void testFromPromptYamlWithSemanticKernelTemplate() throws Exception { - testFromPromptYaml("semantic-kernel"); - } - - @Test - public void testFromPromptYamlWithHandleBarsTemplate() throws Exception { - testFromPromptYaml("handlebars"); - } - - private void testFromPromptYaml(String templateFormat) throws Exception { - String yaml = String.format("name: GenerateStory\n" + - "template: |\n" + - " Tell a story about {{$topic}} that is {{$length}} sentences long.\n" + - "template_format: %s\n" + - "description: A function that generates a story about a topic.\n" + - "input_variables:\n" + - " - name: topic\n" + - " description: The topic of the story.\n" + - " is_required: true\n" + - " - name: length\n" + - " description: The number of sentences in the story.\n" + - " is_required: true\n" + - "output_variable:\n" + - " description: The generated story.\n" + - "execution_settings:\n" + - " default:\n" + - " temperature: 0.6", templateFormat); - @SuppressWarnings({ "rawtypes", "unchecked" }) - KernelFunction expResult = new KernelFunctionFromPrompt.Builder() - .withName("GenerateStory") - .withTemplate("Tell a story about {{$topic}} that is {{$length}} sentences long.") - .withTemplateFormat(templateFormat) - .withDescription("A function that generates a story about a topic.") - .withInputParameters(Arrays.asList( - new InputVariable( - "topic", - "java.lang.String", - "The topic of the story.", - null, - true, - null), - new InputVariable( - "length", - "java.lang.String", - "The number of sentences in the story.", - null, - true, - null))) - .withOutputVariable("The generated story.", "java.lang.String") - .withExecutionSettings(new HashMap() { - { - put("default", PromptExecutionSettings.builder() - .withTemperature(0.6) - .build()); - } - }) - .build(); - - KernelFunction result = KernelFunctionYaml.fromPromptYaml(yaml); - assertNotNull(result); - assertEquals(expResult.getName(), result.getName()); - assertEquals(expResult.getDescription(), result.getDescription()); - assertEqualsJson(expResult.getExecutionSettings(), result.getExecutionSettings()); - assertEquals(expResult.getMetadata(), result.getMetadata()); - } - - public static void assertEqualsJson(Object a, Object b) { - try { - assertEquals(new ObjectMapper().writerWithDefaultPrettyPrinter() - .writeValueAsString(a), - new ObjectMapper().writerWithDefaultPrettyPrinter() - .writeValueAsString(b)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - /** - * Test of fromYaml method, of class KernelFunctionYaml. - * @throws Exception if parsing the YAML throws an Exception - */ - @Test - @Disabled - public void testFromYaml() throws Exception { - System.out.println("fromYaml"); - Path filePath = null; - KernelFunction expResult = null; - KernelFunction result = KernelFunctionYaml.fromYaml(filePath); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfigTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfigTest.java deleted file mode 100644 index 387ae06b6..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfigTest.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static com.microsoft.semantickernel.semanticfunctions.KernelFunctionYamlTest.assertEqualsJson; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import org.junit.jupiter.api.Test; - -@SuppressWarnings("DoubleBraceInitialization") -public class PromptTemplateConfigTest { - - @Test - void testInstanceMadeWithBuilderEqualsInstanceMadeWithConstructor() { - String name = "a name"; - String description = "a description"; - String template = "A template for testing {{plugin.function input}}"; - List inputVariables = Arrays.asList( - new InputVariable("input", "java.lang.String", "a description", "default value", - true, null)); - OutputVariable outputVariable = new OutputVariable("java.lang.String", - "a description"); - - PromptTemplateConfig expected = new PromptTemplateConfig( - PromptTemplateConfig.CURRENT_SCHEMA, - name, - template, - "semantic-kernel", - Collections.emptySet(), - description, - inputVariables, - outputVariable, - new HashMap() { - { - put("default", PromptExecutionSettings.builder().build()); - } - }); - - PromptTemplateConfig result = PromptTemplateConfig.builder() - .withName(name) - .withDescription(description) - .withTemplate(template) - .withInputVariables(inputVariables) - .withOutputVariable(outputVariable) - .withExecutionSettings(new HashMap() { - { - put("default", PromptExecutionSettings.builder().build()); - } - }) - .build(); - - assertEqualsJson(expected, result); - } - - @Test - void testDefaultTemplateBuilder() { - String name = "a name"; - String description = "a description"; - String template = "A template for testing {{plugin.function input}}"; - String templateFormat = "semantic-kernel"; - List inputVariables = Arrays.asList( - new InputVariable("input", "java.lang.String", "a description", "default value", - true, null)); - OutputVariable outputVariable = new OutputVariable("java.lang.String", - "a description"); - HashMap executionSettings = new HashMap() { - { - put("default", PromptExecutionSettings.builder().build()); - } - }; - - PromptTemplateConfig config = PromptTemplateConfig.builder() - .withName(name) - .withTemplate(template) - .withTemplateFormat(templateFormat) - .withDescription(description) - .withInputVariables(inputVariables) - .withOutputVariable(outputVariable) - .withExecutionSettings(executionSettings) - .build(); - - assertEquals(PromptTemplateConfig.CURRENT_SCHEMA, config.getSchema()); - assertEquals(name, config.getName()); - assertEquals(template, config.getTemplate()); - assertEquals(templateFormat, config.getTemplateFormat()); - assertEquals(description, config.getDescription()); - assertEquals(inputVariables, config.getInputVariables()); - assertEquals(outputVariable, config.getOutputVariable()); - assertEquals(executionSettings, config.getExecutionSettings()); - - } - - @Test - void testParseFromJson() throws Exception { - - String name = "a name"; - String description = "a description"; - String template = "A template for testing {{plugin.function input}}"; - String templateFormat = "semantic-kernel"; - List inputVariables = Arrays.asList( - new InputVariable("input", "java.lang.String", "a description", "default value", - true, null)); - OutputVariable outputVariable = new OutputVariable("java.lang.String", - "a description"); - HashMap executionSettings = new HashMap() { - { - put("default", PromptExecutionSettings.builder().build()); - } - }; - - PromptTemplateConfig expected = PromptTemplateConfig.builder() - .withName(name) - .withTemplate(template) - .withTemplateFormat(templateFormat) - .withDescription(description) - .withInputVariables(inputVariables) - .withOutputVariable(outputVariable) - .withExecutionSettings(executionSettings) - .build(); - - String jsonString = "{" - + "\"name\":\"" + name + "\"," - + "\"description\":\"" + description + "\"," - + "\"template\":\"" + template + "\"," - + "\"template_format\":\"" + templateFormat + "\"," - + "\"input_variables\":[" - + "{" - + "\"name\":\"input\"," - + "\"type\":\"java.lang.String\"," - + "\"description\":\"a description\"," - + "\"defaultValue\":\"default value\"," - + "\"is_required\":true" - + "}" - + "]," - + "\"output_variable\":{" - + "\"type\":\"java.lang.String\"," - + "\"description\":\"a description\"" - + "}," - + "\"executionSettings\":{" - + "\"default\":{}" - + "}" - + "}"; - - PromptTemplateConfig result = PromptTemplateConfig.parseFromJson(jsonString); - assertEqualsJson(expected, result); - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactoryTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactoryTest.java deleted file mode 100644 index 67e86d43d..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateFactoryTest.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.semanticfunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import javax.annotation.Nullable; -import org.junit.jupiter.api.Test; - -@SuppressWarnings("DoubleBraceInitialization") -public class PromptTemplateFactoryTest { - - @DefineKernelFunction(name = "function", description = "a function") - public String function( - @Nullable @KernelFunctionParameter(name = "input", description = "the input", type = String.class) String input) { - return String.format("plugin function received: %s", input); - } - - @Test - void createPromptTemplateFromHandlebarsConfig() throws Exception { - executeTest("handlebars"); - } - - @Test - void createPromptTemplateFromDefaultConfig() throws Exception { - executeTest("semantic-kernel"); - } - - private void executeTest(String templateFormat) throws Exception { - - Method method = PromptTemplateFactoryTest.class.getMethod("function", String.class); - List parameters = Collections.singletonList( - new InputVariable("input", String.class.getName(), "the input", "borked", - true, null)); - OutputVariable returnParameter = new OutputVariable<>( - "the output", String.class); - KernelFunction function = KernelFunctionFromMethod.create( - method, - this, - "plugin", - "function", - "this is plugin.function", - parameters, - returnParameter); - - Kernel kernel = Kernel.builder() - .withPlugin(new KernelPlugin( - "plugin", - "a plugin", - new HashMap>() { - { - put("function", function); - } - })) - .build(); - - String name = "a name"; - String description = "a description"; - String template = "semantic-kernel".equals(templateFormat) - ? "A template for testing: {{plugin.function $input}}" - : "A template for testing: {{plugin-function input}}"; - List inputVariables = Arrays.asList( - new InputVariable("input", "java.lang.String", "a description", - "input from config", - true, null)); - OutputVariable outputVariable = new OutputVariable("java.lang.String", - "a description"); - HashMap executionSettings = new HashMap() { - { - put("default", PromptExecutionSettings.builder().build()); - } - }; - - PromptTemplateConfig config = PromptTemplateConfig.builder() - .withName(name) - .withTemplate(template) - .withTemplateFormat(templateFormat) - .withDescription(description) - .withInputVariables(inputVariables) - .withOutputVariable(outputVariable) - .withExecutionSettings(executionSettings) - .build(); - - PromptTemplate promptTemplate = PromptTemplateFactory.build(config); - - KernelArguments args = KernelArguments.builder() - .withInput(ContextVariable.of("input from args")).build(); - - String expected = String.format("A template for testing: %s", - function((String) args.getInput().getValue())); - String renderedPrompt = promptTemplate.renderAsync(kernel, args, null).block(); - assertEquals(expected, renderedPrompt); - } -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/services/AIServiceSelectorTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/services/AIServiceSelectorTest.java deleted file mode 100644 index 13ee076f1..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/services/AIServiceSelectorTest.java +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.services; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; - -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import org.junit.jupiter.api.Test; - -public class AIServiceSelectorTest { - - @Test - public void testReturnsRequestedType() { - - AIService aService = new AIService() { - @Override - public String getModelId() { - return "a-model"; - } - - @Override - public String getServiceId() { - return "a-service"; - } - }; - - AIService bService = new AIService() { - @Override - public String getModelId() { - return "b-model"; - } - - @Override - public String getServiceId() { - return "b-service"; - } - }; - - AIServiceSelection expected = new AIServiceSelection<>(aService, null); - - Kernel kernel = Kernel.builder() - .withAIService((Class) aService.getClass(), aService) - .withAIService((Class) bService.getClass(), bService) - .build(); - - AIServiceSelector selector = kernel.getServiceSelector(); - - AIServiceSelection actual = selector.trySelectAIService(aService.getClass(), null, null); - assertNotNull(actual); - assertNull(actual.getSettings()); - assertEquals(expected.getService(), actual.getService()); - } - - // used to test that the selector returns the requested super type - interface TestService extends AIService { - } - - @Test - public void testReturnsRequestedSuperType() { - - AIService aService = new TestService() { - @Override - public String getModelId() { - return "a-model"; - } - - @Override - public String getServiceId() { - return "a-service"; - } - }; - - AIService bService = new AIService() { - @Override - public String getModelId() { - return "b-model"; - } - - @Override - public String getServiceId() { - return "b-service"; - } - }; - - AIServiceSelection expected = new AIServiceSelection<>(aService, null); - - Kernel kernel = Kernel.builder() - .withAIService((Class) aService.getClass(), aService) - .withAIService((Class) bService.getClass(), bService) - .build(); - - AIServiceSelector selector = kernel.getServiceSelector(); - - AIServiceSelection actual = selector.trySelectAIService(TestService.class, null, null); - assertNotNull(actual); - assertNull(actual.getSettings()); - assertEquals(expected.getService(), actual.getService()); - } - - @Test - public void testReturnsUsingKernelFunction() { - - AIService aService = new AIService() { - @Override - public String getModelId() { - return "a-model"; - } - - @Override - public String getServiceId() { - return "a-service"; - } - }; - - AIService bService = new AIService() { - @Override - public String getModelId() { - return "b-model"; - } - - @Override - public String getServiceId() { - return "b-service"; - } - }; - - PromptExecutionSettings settings = PromptExecutionSettings.builder() - .withServiceId("a-service").build(); - AIServiceSelection expected = new AIServiceSelection<>(aService, settings); - - PromptTemplateConfig promptTemplateConfig = PromptTemplateConfig.defaultTemplateBuilder() - .withTemplate("{{aFunction 'input'}}") - .build(); - - KernelFunction function = KernelFunction.createFromPrompt(promptTemplateConfig) - .withDefaultExecutionSettings(settings) - .build(); - - Kernel kernel = Kernel.builder() - .withAIService((Class) aService.getClass(), aService) - .withAIService((Class) bService.getClass(), bService) - .build(); - - AIServiceSelector selector = kernel.getServiceSelector(); - - // AIService could match aService or bService. Selector should use function to refine the selection. - AIServiceSelection actual = selector.trySelectAIService(AIService.class, function, null); - assertNotNull(actual); - assertEquals(expected.getSettings(), actual.getSettings()); - assertEquals(expected.getService(), actual.getService()); - - } - - @Test - public void testReturnsUsingKernelFunctionArguments() { - - AIService aService = new AIService() { - @Override - public String getModelId() { - return "a-model"; - } - - @Override - public String getServiceId() { - return "a-service"; - } - }; - - AIService bService = new AIService() { - @Override - public String getModelId() { - return "b-model"; - } - - @Override - public String getServiceId() { - return "b-service"; - } - }; - - AIServiceSelection expected = new AIServiceSelection<>(aService, null); - - KernelArguments arguments = KernelArguments.builder().build(); - - Kernel kernel = Kernel.builder() - .withAIService((Class) aService.getClass(), aService) - .withAIService((Class) bService.getClass(), bService) - .build(); - - AIServiceSelector selector = kernel.getServiceSelector(); - - // arguments are not used in the current implementation - // Could select either aService or bService. - AIServiceSelection actual = selector.trySelectAIService(AIService.class, null, - arguments); - assertNotNull(actual); - assertNull(actual.getSettings()); - assertNotNull(expected.getService()); - } - -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateTest.java deleted file mode 100644 index 3a31de30e..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateTest.java +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.templateengine.handlebars; - -import static java.util.stream.Collectors.joining; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.microsoft.semantickernel.Kernel; -import com.microsoft.semantickernel.contextvariables.ContextVariable; -import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; -import com.microsoft.semantickernel.contextvariables.converters.ContextVariableJacksonConverter; -import com.microsoft.semantickernel.orchestration.InvocationContext; -import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; -import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; -import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; -import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; -import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import org.apache.commons.text.StringEscapeUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author davidgrieve - */ -public class HandlebarsPromptTemplateTest { - - public HandlebarsPromptTemplateTest() { - } - - public static void main(String[] args) { - new HandlebarsPromptTemplateTest().testRenderAsync(); - } - - public static class StringFunctions { - - @DefineKernelFunction(name = "upper", description = "Converts a string to upper case.") - public String upper( - @KernelFunctionParameter(name = "input", required = true, description = "The string to convert to upper case", type = String.class) String input) { - return input.toUpperCase(Locale.ROOT); - } - - @DefineKernelFunction(name = "concat", description = "Concatenate the second string to the first string.") - public String concat( - @KernelFunctionParameter(name = "input", required = true, description = "The string to which the second string is concatenated.", type = String.class) String first, - @KernelFunctionParameter(name = "suffix", required = true, description = "The string which is concatenated to the first string.", type = String.class) String suffix) { - return first.concat(suffix); - } - - } - - /** - * Test of renderAsync method, of class HandlebarsPromptTemplate. - */ - @Test - void testRenderAsync() { - - List choices = Arrays.asList("CHOICE-A", "CHOICE-B"); - - List history = Arrays.asList( - new ChatHistory( - Arrays.asList( - ChatMessageTextContent.systemMessage("a"), - ChatMessageTextContent.userMessage("b"))), - new ChatHistory( - Arrays.asList( - ChatMessageTextContent.systemMessage("c"), - ChatMessageTextContent.userMessage("d")))); - - KernelPlugin kernelPlugin = KernelPluginFactory.createFromObject( - new StringFunctions(), - "string"); - - Kernel kernel = Kernel.builder() - .withPlugin(kernelPlugin) - .build(); - - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate( - "{{choices.[0]}}\n" + - "{{choices}}\n" + - "{{#each history}}\n" + - " {{#each this}}\n" + - " {{string-upper content}}\n" + - " {{/each}}\n" + - "{{/each}}\n" + - "Hello World") - // "{{string-concat input suffix}}") TODO - this is not working - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", "Hello ") - .withVariable("suffix", "World") - .withVariable("choices", choices) - .withVariable("history", history) - .withVariable("kernelPlugins", Arrays.asList(kernelPlugin)) - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = "CHOICE-A [CHOICE-A, CHOICE-B] A B C D Hello World"; - - String result = instance.renderAsync(kernel, arguments, null).block(); - assertNotNull(result); - - String normalizedResult = - // split result into lines - Arrays.stream(result.split("\\r?\\n|\\r")) - // remove leading and trailing whitespace - .map(String::trim) - // remove empty lines - .filter(s -> !s.isEmpty()) - // put it back together - .collect(joining(" ")); - assertEquals(expResult, normalizedResult); - } - - public static class Foo { - - @JsonProperty("val") - private final String val; - - public Foo(String val) { - this.val = val; - } - - public String getVal() { - return val; - } - } - - @Test - public void testSerializesObject() { - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate("{{input}}") - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", new Foo("bar"), - ContextVariableJacksonConverter.create(Foo.class)) - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = StringEscapeUtils.escapeXml11("{ \"val\" : \"bar\"}"); - - String result = instance.renderAsync(Kernel.builder().build(), arguments, null) - .block(); - Assertions.assertEquals(expResult, result.replaceAll("\\r\\n|\\r|\\n", "")); - } - - @Test - public void testMessageContent() { - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate( - "{{#each input}}\n" + - "{{content}}\n" + - "{{/each}}") - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", new ChatHistory() - .addAssistantMessage("foo") - .addUserMessage("bar\"<>&")) - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = "foobar"<>&"; - - String result = instance.renderAsync(Kernel.builder().build(), arguments, null) - .block(); - Assertions.assertEquals(expResult, result.replaceAll("\\n", "")); - } - - @Test - public void testMessageHandler() { - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate("{{#message role=\"user\"}}\n" + - "{{input}}\n" + - "{{/message}}") - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", "bar\"<>&") - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = "bar"<>&"; - - String result = instance.renderAsync(Kernel.builder().build(), arguments, null) - .block(); - Assertions.assertEquals(expResult, result.replaceAll("\\n", "")); - } - - @Test - public void iterableWithContextVariable() { - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate( - "{{#each input}}" + - "{{this}}" + - "{{/each}}") - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", Arrays.asList(ContextVariable.of("foo\"<>&"))) - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = "foo"<>&"; - - String result = instance.renderAsync(Kernel.builder().build(), arguments, null) - .block(); - Assertions.assertEquals(expResult, result.replaceAll("\\n", "")); - } - - @Test - public void withCustomConverter() { - PromptTemplateConfig promptTemplate = PromptTemplateConfig.builder() - .withTemplate("{{#each input}}{{this}}{{/each}}") - .withTemplateFormat("handlebars") - .build(); - - HandlebarsPromptTemplate instance = new HandlebarsPromptTemplate(promptTemplate); - - ContextVariableTypeConverter converter = ContextVariableTypeConverter.builder( - Foo.class) - .toPromptString(Foo::getVal) - .build(); - KernelArguments arguments = KernelArguments.builder() - .withVariable("input", ContextVariable.of(new Foo("bar\"<>&"), converter)) - .build(); - - // Return from renderAsync is normalized to remove empty lines and leading/trailing whitespace - String expResult = "bar"<>&"; - - String result = instance.renderAsync(Kernel.builder().build(), arguments, - InvocationContext.builder() - .withContextVariableConverter(converter) - .build()) - .block(); - Assertions.assertEquals(expResult, result.replaceAll("\\n", "")); - } -} \ No newline at end of file diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/semantickernel/CodeTokenizerTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/semantickernel/CodeTokenizerTest.java deleted file mode 100644 index d39c6aaff..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/templateengine/semantickernel/CodeTokenizerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.templateengine.semantickernel; - -import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.CodeTokenizer; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.Block; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.FunctionIdBlock; -import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.NamedArgBlock; -import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class CodeTokenizerTest { - - @Test - public void parseNamedArgs1() { - List tokens = new CodeTokenizer().tokenize( - "MyFunction street=$street zip=\"98123\" city=\"Seattle\""); - - Assertions.assertEquals(4, tokens.size()); - - FunctionIdBlock function = (FunctionIdBlock) tokens.get(0); - Assertions.assertEquals("MyFunction", function.getFunctionName()); - Assertions.assertEquals("", function.getPluginName()); - - NamedArgBlock namedArgBlock = (NamedArgBlock) tokens.get(1); - Assertions.assertEquals("street", namedArgBlock.getName()); - Assertions.assertEquals("123 Main St", namedArgBlock.getValue( - new ContextVariableTypes(), - KernelArguments.builder() - .withVariable("street", "123 Main St") - .build())); - - namedArgBlock = (NamedArgBlock) tokens.get(2); - Assertions.assertEquals("zip", namedArgBlock.getName()); - Assertions.assertEquals("98123", namedArgBlock.getValue( - new ContextVariableTypes(), - KernelArguments.builder().build())); - - namedArgBlock = (NamedArgBlock) tokens.get(3); - Assertions.assertEquals("city", namedArgBlock.getName()); - Assertions.assertEquals("Seattle", namedArgBlock.getValue( - new ContextVariableTypes(), - KernelArguments.builder().build())); - } - - @Test - public void parseNamedArgs2() { - List tokens = new CodeTokenizer().tokenize( - "MyFunction recall='where did I grow up?'"); - - Assertions.assertEquals(2, tokens.size()); - - FunctionIdBlock function = (FunctionIdBlock) tokens.get(0); - Assertions.assertEquals("MyFunction", function.getFunctionName()); - Assertions.assertEquals("", function.getPluginName()); - - NamedArgBlock namedArgBlock = (NamedArgBlock) tokens.get(1); - Assertions.assertEquals("recall", namedArgBlock.getName()); - Assertions.assertEquals("where did I grow up?", namedArgBlock.getValue( - new ContextVariableTypes(), - KernelArguments.builder().build())); - } -} diff --git a/semantickernel-api/src/test/java/com/microsoft/semantickernel/text/TextChunkerTest.java b/semantickernel-api/src/test/java/com/microsoft/semantickernel/text/TextChunkerTest.java deleted file mode 100644 index 6b7c01c76..000000000 --- a/semantickernel-api/src/test/java/com/microsoft/semantickernel/text/TextChunkerTest.java +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -package com.microsoft.semantickernel.text; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TextChunkerTest { - - @Test - public void canSplitPlainTextLines() { - String input = "This is a test of the emergency broadcast system. This is only a test."; - List expected = Arrays.asList( - "This is a test of the emergency broadcast system.", - "This is only a test."); - - List result = TextChunker.splitPlainTextLines(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitPlainTextLinesWithComma() { - String input = "This is a test, of the emergency broadcast system. This is only a test."; - List expected = Arrays.asList( - "This is a test,", - "of the emergency broadcast system.", - "This is only a test."); - - List result = TextChunker.splitPlainTextLines(input, 10); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitPlainTextLinesLongString() { - String input = "This is a very very very very very very long string with nothing to split on."; - List expected = Arrays.asList( - "This is a very very very very very very", - "long string with nothing to split on."); - - List result = TextChunker.splitPlainTextLines(input, 10); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitPlainTextLinesLongStringWithSmallTokenCount() { - String input = "This is a very very very very very very very very very very very long string."; - List expected = Arrays.asList( - "This is a", - "very very", - "very very", - "very very", - "very very", - "very very", - "very long", - "string."); - - List result = TextChunker.splitPlainTextLines(input, 2); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitPlainTextLinesNoSeparator() { - String input = "Thisisaveryveryveryveryveryverylongstringwithnothingtospliton"; - List expected = Arrays.asList("Thisisaveryveryveryveryveryver", - "ylongstringwithnothingtospliton"); - - List result = TextChunker.splitPlainTextLines(input, 10); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitMarkdownParagraphs() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system. This is only a test.", - "We repeat, this is only a test. A unit test."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system.", - "This is only a test.", - "We repeat, this is only a test. A unit test."); - - List result = TextChunker.splitMarkdownParagraphs(input, 13); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphs() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system. This is only a test.", - "We repeat, this is only a test. A unit test."); - - List expected = Arrays.asList( - "This is a test of the emergency broadcast system.", - "This is only a test.", - "We repeat, this is only a test. A unit test."); - - List result = TextChunker.splitPlainTextParagraphs(input, 13); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitMarkdownParagraphsWithEmptyInput() { - List input = Collections.emptyList(); - - List expected = Collections.emptyList(); - - List result = TextChunker.splitMarkdownParagraphs(input, 13); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsEvenly() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system. This is only a test.", - "We repeat, this is only a test. A unit test.", - "A small note. And another. And once again. Seriously, this is the end." - + " We're finished. All set. Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system.", - "This is only a test.", - "We repeat, this is only a test. A unit test.", - "A small note. And another. And once again.", - "Seriously, this is the end. We're finished. All set. Bye. Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnNewlines() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system\r\nThis is only a test", - "We repeat this is only a test\nA unit test", - "A small note\n" - + "And another\r\n" - + "And once again\r" - + "Seriously this is the end\n" - + "We're finished\n" - + "All set\n" - + "Bye\n", - "Done"); - - List expected = Arrays.asList( - "This is a test of the emergency broadcast system", - "This is only a test", - "We repeat this is only a test\nA unit test", - "A small note\nAnd another\nAnd once again", - "Seriously this is the end\nWe're finished\nAll set\nBye Done"); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnPunctuation() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system. This is only a test", - "We repeat, this is only a test? A unit test", - "A small note! And another? And once again! Seriously, this is the end." - + " We're finished. All set. Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system.", - "This is only a test", - "We repeat, this is only a test? A unit test", - "A small note! And another? And once again!", - "Seriously, this is the end.", - "We're finished. All set. Bye.\nDone."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnSemicolons() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system; This is only a test", - "We repeat; this is only a test; A unit test", - "A small note; And another; And once again; Seriously, this is the end;" - + " We're finished; All set; Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system;", - "This is only a test", - "We repeat; this is only a test; A unit test", - "A small note; And another; And once again;", - "Seriously, this is the end; We're finished; All set; Bye. Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnColons() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system: This is only a test", - "We repeat: this is only a test: A unit test", - "A small note: And another: And once again: Seriously, this is the end:" - + " We're finished: All set: Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system:", - "This is only a test", - "We repeat: this is only a test: A unit test", - "A small note: And another: And once again:", - "Seriously, this is the end: We're finished: All set: Bye. Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnCommas() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system, This is only a test", - "We repeat, this is only a test, A unit test", - "A small note, And another, And once again, Seriously, this is the end," - + " We're finished, All set, Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency broadcast system,", - "This is only a test", - "We repeat, this is only a test, A unit test", - "A small note, And another, And once again, Seriously,", - "this is the end, We're finished, All set, Bye." + "\n" + "Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnClosingBrackets() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system) This is only a test", - "We repeat) this is only a test) A unit test", - "A small note] And another) And once again] Seriously this is the end}" - + " We're finished} All set} Bye.", - "Done."); - - List expected = Arrays.asList( - "This is a test of the emergency broadcast system)", - "This is only a test", - "We repeat) this is only a test) A unit test", - "A small note] And another) And once again]", - "Seriously this is the end} We're finished} All set} Bye. Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsOnHyphens() { - List input = Arrays.asList( - "This is a test of the emergency broadcast system-This is only a test", - "We repeat-this is only a test-A unit test", - "A small note-And another-And once again-Seriously, this is the end-We're" - + " finished-All set-Bye.", - "Done."); - List expected = Arrays.asList( - "This is a test of the emergency", - "broadcast system-This is only a test", - "We repeat-this is only a test-A unit test", - "A small note-And another-And once again-Seriously,", - "this is the end-We're finished-All set-Bye." + "\n" + "Done."); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitTextParagraphsWithNoDelimiters() { - List input = Arrays.asList( - "Thisisatestoftheemergencybroadcastsystem", - "Thisisonlyatest", - "WerepeatthisisonlyatestAunittest", - "AsmallnoteAndanotherAndonceagain", - "SeriouslythisistheendWe'refinishedAllsetByeDoneThisOneWillBeSplitToMeetTheLimit"); - List expected = Arrays.asList( - "Thisisatestoftheemergencybroadcastsystem" + "\n" + "Thisisonlyatest", - "WerepeatthisisonlyatestAunittest", - "AsmallnoteAndanotherAndonceagain", - "SeriouslythisistheendWe'refinishedAllse", - "tByeDoneThisOneWillBeSplitToMeetTheLimit"); - - List result = TextChunker.splitPlainTextParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } - - @Test - public void canSplitMarkdownParagraphsOnNewlines() { - List input = Arrays.asList( - "This_is_a_test_of_the_emergency_broadcast_system\r\nThis_is_only_a_test", - "We_repeat_this_is_only_a_test\nA_unit_test", - "A_small_note\n" - + "And_another\r\n" - + "And_once_again\r" - + "Seriously_this_is_the_end\n" - + "We're_finished\n" - + "All_set\n" - + "Bye\n", - "Done"); - - List expected = Arrays.asList( - "This_is_a_test_of_the_emergency_broadcast_system", - "This_is_only_a_test", - "We_repeat_this_is_only_a_test\nA_unit_test", - "A_small_note\nAnd_another\nAnd_once_again", - "Seriously_this_is_the_end\nWe're_finished\nAll_set\nBye Done"); - - List result = TextChunker.splitMarkdownParagraphs(input, 15); - - Assertions.assertEquals(expected, result); - } -} diff --git a/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/config.json b/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/config.json deleted file mode 100644 index f8f0a42d7..000000000 --- a/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema": 1, - "description": "Sample plugin loaded via resources", - "execution_settings": { - "default": { - "max_tokens": 150, - "temperature": 0.9, - "top_p": 0.0, - "presence_penalty": 0.6, - "frequency_penalty": 0.0 - } - }, - "input_variables": [ - { - "name": "prompt", - "type": "string", - "description": "The prompt to generate text from" - } - ], - "output_variables": { - "type": "string", - "description": "The generated text" - } -} \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt b/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt deleted file mode 100644 index ddd3f836d..000000000 --- a/semantickernel-api/src/test/resources/Plugins/ExamplePlugins/ExampleFunction/skprompt.txt +++ /dev/null @@ -1 +0,0 @@ -This is an example \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties deleted file mode 100644 index 6535223b2..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle.properties +++ /dev/null @@ -1 +0,0 @@ -test_top=Top level value \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en.properties b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en.properties deleted file mode 100644 index 8f7fc02e8..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en.properties +++ /dev/null @@ -1 +0,0 @@ -test_language=English test value \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en_GB.properties b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en_GB.properties deleted file mode 100644 index 9acef1680..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/localization/ResourceBundle_en_GB.properties +++ /dev/null @@ -1 +0,0 @@ -test_language_country=GB english test value \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response1.txt b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response1.txt deleted file mode 100644 index 18b36dbe6..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response1.txt +++ /dev/null @@ -1,4 +0,0 @@ -[THOUGHT PROCESS] - -[QUESTION] -What year did the first world cup take place? diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response2.txt b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response2.txt deleted file mode 100644 index 76c35d0b8..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response2.txt +++ /dev/null @@ -1,2 +0,0 @@ -[THOUGHT] To answer this question, we need to find out the year of the first world cup and then divide it by 2. We can use a web search to find the year of the first world cup and then perform the necessary calculation. -[ACTION] {{"action": "WebSearch.search","action_variables": {"query":"first world cup year","count":"1"}}} \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response3.txt b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response3.txt deleted file mode 100644 index 3eb1a7d24..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response3.txt +++ /dev/null @@ -1,2 +0,0 @@ -[THOUGHT] Now that we know the year of the first world cup is 1930, we can divide it by 2 to get the answer to the original question. -[ACTION] {{"action": "AdvancedCalculator.Calculator","action_variables": {"input":"1930/2"}}} \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response4.txt b/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response4.txt deleted file mode 100644 index eb869bc5f..000000000 --- a/semantickernel-api/src/test/resources/com/microsoft/semantickernel/planner/stepwiseplanner/response4.txt +++ /dev/null @@ -1,2 +0,0 @@ -[FINAL ANSWER] -The year of the first world cup is 1930, and when divided by 2, the result is 965. \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/log4j2.xml b/semantickernel-api/src/test/resources/log4j2.xml deleted file mode 100644 index 50a638f0d..000000000 --- a/semantickernel-api/src/test/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/semantickernel-api/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/semantickernel-api/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker deleted file mode 100644 index ca6ee9cea..000000000 --- a/semantickernel-api/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ /dev/null @@ -1 +0,0 @@ -mock-maker-inline \ No newline at end of file diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml deleted file mode 100644 index 372e04c1f..000000000 --- a/semantickernel-bom/pom.xml +++ /dev/null @@ -1,331 +0,0 @@ - - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-bom - 1.4.4-RC3-SNAPSHOT - pom - - Semantic Kernel Java BOM - Bill of Materials for all Semantic Kernel (Java) modules - https://www.github.com/microsoft/semantic-kernel - - - 2.18.0 - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.5.0 - - - enforce-maven - - enforce - - - - - 3.9.9 - - - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.8.0 - - - - - - - - - io.opentelemetry - opentelemetry-bom - 1.43.0 - pom - import - - - com.microsoft.semantic-kernel - semantickernel-api - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-experimental - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-gpt3-tokenizer - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-plugin-core - ${project.version} - - - com.microsoft.semantic-kernel - aiservices-azureopenai - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-aiservices-huggingface - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-aiservices-openai - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-aiservices-google - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-azureaisearch - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-jdbc - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-mysql - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-sqlite - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-hsqldb - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-oracle - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-redis - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-agents-core - ${project.version} - - - com.microsoft.semantic-kernel - semantickernel-data-postgres - ${project.version} - - - - com.azure - azure-ai-openai - 1.0.0-beta.16 - - - com.azure - azure-identity - 1.14.0 - - - com.azure - azure-core - 1.53.0 - - - com.azure - azure-search-documents - 11.8.0-beta.1 - - - com.azure - azure-core-serializer-json-jackson - - - - - redis.clients - jedis - 5.2.0 - - - - com.fasterxml.jackson.core - jackson-annotations - ${com.fasterxml.jackson.core.version} - - - com.fasterxml.jackson.core - jackson-databind - ${com.fasterxml.jackson.core.version} - runtime - - - com.fasterxml.jackson.core - jackson-core - ${com.fasterxml.jackson.core.version} - runtime - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - ${com.fasterxml.jackson.core.version} - runtime - - - - com.github.jknack - handlebars - 4.3.1 - - - jakarta.inject - jakarta.inject-api - 2.0.1.MR - - - org.slf4j - slf4j-api - 2.0.16 - - - com.google.code.findbugs - jsr305 - 3.0.2 - - - - - javax.xml.stream - stax-api - 1.0-2 - provided - - - - com.github.spotbugs - spotbugs-annotations - 4.8.6 - - - org.apache.commons - commons-text - 1.14.0 - - - - com.google.cloud - google-cloud-vertexai - 1.12.0 - - - - com.github.victools - jsonschema-generator - 4.36.0 - true - - - com.github.victools - jsonschema-module-jackson - 4.36.0 - true - - - io.projectreactor - reactor-core - 3.7.8 - - - - - - - - release - - - - ${releaseRepoId} - - ${releaseRepoUrl} - ${releaseRepoName} - - - - - github-packages - - false - - - - github - GitHub Packages - https://maven.pkg.github.com/microsoft/semantic-kernel-java - - - - - central - https://repo1.maven.org/maven2 - - - github - GitHub Packages - https://maven.pkg.github.com/microsoft/semantic-kernel-java - - true - - - - - - - - - microsoft - Microsoft - - - - - - MIT License - https://opensource.org/licenses/MIT - repo - - - - - https://github.com/microsoft/semantic-kernel - scm:git:https://github.com/microsoft/semantic-kernel.git - scm:git:https://github.com/microsoft/semantic-kernel.git - HEAD - - diff --git a/semantickernel-experimental/pom.xml b/semantickernel-experimental/pom.xml deleted file mode 100644 index 5cdbd5349..000000000 --- a/semantickernel-experimental/pom.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - 4.0.0 - - com.microsoft.semantic-kernel - semantickernel-parent - 1.4.4-RC3-SNAPSHOT - - - semantickernel-experimental - jar - Semantic Kernel Experimental API - Defines the public interface for the Semantic Kernel experimental features - - - com.azure - azure-ai-openai - - - org.slf4j - slf4j-api - - - com.fasterxml.jackson.core - jackson-databind - compile - - - com.fasterxml.jackson.core - jackson-core - compile - - - com.github.jknack - handlebars - - - com.google.code.findbugs - jsr305 - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - compile - - - com.github.spotbugs - spotbugs-annotations - - - org.apache.commons - commons-text - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.wiremock - wiremock - test - - - - javax.xml.stream - stax-api - provided - - - - org.mockito - mockito-junit-jupiter - test - - - io.opentelemetry - opentelemetry-api - - - - - com.microsoft.semantic-kernel - semantickernel-api - - - com.microsoft.semantic-kernel - semantickernel-api-builders - provided - - - - - redis.clients - jedis - - - - - com.azure - azure-search-documents - - - com.azure - azure-core-serializer-json-jackson - - - - - - org.postgresql - postgresql - 42.7.7 - - - org.xerial - sqlite-jdbc - 3.47.0.0 - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - 1 - - - - - - \ No newline at end of file diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml deleted file mode 100644 index e8a2357ac..000000000 --- a/spotbugs-exclude.xml +++ /dev/null @@ -1,3 +0,0 @@ - - -