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));
}