diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 49d85a8c3..148512f88 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,3 +11,12 @@ updates: commit-message: # Prefix all commit messages with "chore: " prefix: "chore" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "wednesday" + time: "09:00" + commit-message: + # Prefix all commit messages with "chore: " + prefix: "chore" diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index db543e7dc..9686aefc2 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -6,7 +6,7 @@ on: jobs: gitlab-dev-deploy: if: ${{ github.event.registry_package.package_version.container_metadata.tag.name == 'development' }} - uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.6.0 with: gitlab-project-id: "1826" gitlab-project-ref: "master" diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 8aef1e8d8..c2e903e9b 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -9,6 +9,6 @@ on: jobs: pr-title-check: - uses: epam/ai-dial-ci/.github/workflows/pr-title-check.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/pr-title-check.yml@1.6.0 secrets: ACTIONS_BOT_TOKEN: ${{ secrets.ACTIONS_BOT_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 000000000..7cd651020 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,10 @@ +name: PR Workflow + +on: + pull_request: + branches: [development, release-*] + +jobs: + run_tests: + uses: epam/ai-dial-ci/.github/workflows/java_pr.yml@1.6.0 + secrets: inherit diff --git a/.github/workflows/pr_check_tests.yml b/.github/workflows/pr_check_tests.yml deleted file mode 100644 index 36d8d7f34..000000000 --- a/.github/workflows/pr_check_tests.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Code checks - tests - -on: - pull_request: - branches: - - development - - release-* - -jobs: - run_tests: - uses: epam/ai-dial-ci/.github/workflows/test_gradle_docker.yml@1.3.1 - secrets: inherit - with: - bypass_checks: false - java_version: 17 - java_distribution: temurin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e5b562a84..4cf31383d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,13 +1,10 @@ -name: Release version +name: Release Workflow on: push: branches: [development, release-*] -env: - IMAGE_NAME: ${{ github.repository }} - jobs: release: - uses: epam/ai-dial-ci/.github/workflows/publish_gradle_docker.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/java_release.yml@1.6.0 secrets: inherit diff --git a/README.md b/README.md index 457babf7c..59f80d066 100644 --- a/README.md +++ b/README.md @@ -141,9 +141,9 @@ Dynamic settings include: | applications | A list of deployed AI DIAL Applications and their parameters:
``: Unique application name. | | applications. | `endpoint`: AI DIAL Application API for chat completions.
`iconUrl`: Icon path for the AI DIAL Application on UI.
`description`: Brief AI DIAL Application description.
`displayName`: AI DIAL Application name on UI.
`inputAttachmentTypes`: A list of allowed MIME types for the input attachments.
`maxInputAttachments`: Maximum number of input attachments (default is zero when `inputAttachmentTypes` is unset, otherwise, infinity) | | models | A list of deployed models and their parameters:
``: Unique model name. | -| models. | `type`: Model type—`chat` or `embedding`.
`iconUrl`: Icon path for the model on UI.
`description`: Brief model description.
`displayName`: Model name on UI.
`displayVersion`: Model version on UI.
`endpoint`: Model API for chat completions or embeddings.
`features`: Model features.
`limits`: Model token limits.
`pricing`: Model pricing.
`upstreams`: Used for load-balancing—request is sent to model endpoint containing X-UPSTREAM-ENDPOINT and X-UPSTREAM-KEY headers. | +| models. | `type`: Model type—`chat` or `embedding`.
`iconUrl`: Icon path for the model on UI.
`description`: Brief model description.
`displayName`: Model name on UI.
`displayVersion`: Model version on UI.
`endpoint`: Model API for chat completions or embeddings.
`tokenizerModel`: Identifies the specific model whose tokenization algorithm exactly matches that of the referenced model. This is typically the name of the earliest-released model in a series of models sharing an identical tokenization algorithm (e.g. `gpt-3.5-turbo-0301`, `gpt-4-0314`, or `gpt-4-1106-vision-preview`). This parameter is essential for DIAL clients that reimplement tokenization algorithms on their side, instead of utilizing the `tokenizeEndpoint` provided by the model.
`features`: Model features.
`limits`: Model token limits.
`pricing`: Model pricing.
`upstreams`: Used for load-balancing—request is sent to model endpoint containing X-UPSTREAM-ENDPOINT and X-UPSTREAM-KEY headers. | | models..limits | `maxPromptTokens`: maximum number of tokens in a completion request.
`maxCompletionTokens`: maximum number of tokens in a completion response.
`maxTotalTokens`: maximum number of tokens in completion request and response combined.
Typically either `maxTotalTokens` is specified or `maxPromptTokens` and `maxCompletionTokens`. | -| models..pricing | `unit`: the pricing units (currently only `token` is supported).
`prompt`: per-unit price for the completion request in USD.
`completion`: per-unit price for the completion response in USD. | +| models..pricing | `unit`: the pricing units (currently `token` and `char_without_whitespace` are supported).
`prompt`: per-unit price for the completion request in USD.
`completion`: per-unit price for the completion response in USD. | | models..features | `rateEndpoint`: endpoint for rate requests *(exposed by core as `/rate`)*.
`tokenizeEndpoint`: endpoint for requests to the model tokenizer *(exposed by core as `/tokenize`)*.
`truncatePromptEndpoint`: endpoint for truncating prompt requests *(exposed by core as `/truncate_prompt`)*.
`systemPromptSupported`: does the model support system prompt (default is `true`).
`toolsSupported`: does the model support tools (default is `false`).
`seedSupported`: does the model support `seed` request parameter (default is `false`) | | models..upstreams | `endpoint`: Model endpoint.
`key`: Your API key. | | keys | API Keys parameters:
``: Your API key. | diff --git a/src/main/java/com/epam/aidial/core/controller/DeploymentPostController.java b/src/main/java/com/epam/aidial/core/controller/DeploymentPostController.java index be24ef6f7..3cd95586f 100644 --- a/src/main/java/com/epam/aidial/core/controller/DeploymentPostController.java +++ b/src/main/java/com/epam/aidial/core/controller/DeploymentPostController.java @@ -199,7 +199,7 @@ void handleRequestBody(Buffer requestBody) { ObjectNode tree = (ObjectNode) ProxyUtil.MAPPER.readTree(stream); try { - ProxyUtil.collectAttachedFiles(tree, link -> processAttachedFile(link, context.getProxyApiKeyData())); + ProxyUtil.collectAttachedFiles(tree, this::processAttachedFile); } catch (HttpException e) { respond(e.getStatus(), e.getMessage()); log.warn("Can't collect attached files. Trace: {}. Span: {}. Error: {}", @@ -249,14 +249,19 @@ void handleRequestBody(Buffer requestBody) { sendRequest(); } - private void processAttachedFile(String url, ApiKeyData apiKeyData) { + private void processAttachedFile(String url) { ResourceDescription resource = getResourceDescription(url); if (resource == null) { return; } + String resourceUrl = resource.getUrl(); + ApiKeyData sourceApiKeyData = context.getApiKeyData(); + ApiKeyData destApiKeyData = context.getProxyApiKeyData(); AccessService accessService = proxy.getAccessService(); - if (accessService.hasWriteAccess(resource, context) || accessService.isSharedResource(resource, context)) { - apiKeyData.getAttachedFiles().add(resource.getUrl()); + if (accessService.hasWriteAccess(resource, context) + || accessService.isSharedResource(resource, context) + || sourceApiKeyData.getAttachedFiles().contains(resourceUrl)) { + destApiKeyData.getAttachedFiles().add(resourceUrl); } else { throw new HttpException(HttpStatus.FORBIDDEN, "Access denied to the file %s".formatted(url)); }