Compare commits
44 Commits
main
...
release/0.
| Author | SHA1 | Date |
|---|---|---|
|
|
903cf33342 | 12 months ago |
|
|
4b938ab18d | 12 months ago |
|
|
88356de923 | 12 months ago |
|
|
5f09900dca | 1 year ago |
|
|
9ac99abf20 | 1 year ago |
|
|
32588f562e | 1 year ago |
|
|
36f8bd3f1a | 1 year ago |
|
|
c919074e06 | 1 year ago |
|
|
88cd9aedb7 | 1 year ago |
|
|
16a4f77fb4 | 1 year ago |
|
|
3401c52665 | 1 year ago |
|
|
4fa3d78ed8 | 1 year ago |
|
|
5f7f851b17 | 1 year ago |
|
|
559ab46ee1 | 1 year ago |
|
|
df98223c8c | 1 year ago |
|
|
144f9507f8 | 1 year ago |
|
|
2e097a1ac0 | 1 year ago |
|
|
9f7d8a981f | 1 year ago |
|
|
40b31bafd5 | 1 year ago |
|
|
d38a2c95fb | 1 year ago |
|
|
7d18e2a0ef | 1 year ago |
|
|
024f242251 | 1 year ago |
|
|
bfdce78ca5 | 1 year ago |
|
|
00c2258352 | 1 year ago |
|
|
a1b3d41712 | 1 year ago |
|
|
b26e20fe34 | 1 year ago |
|
|
161ff432f1 | 1 year ago |
|
|
99a9def623 | 1 year ago |
|
|
fe1846c437 | 1 year ago |
|
|
8e75eb5c63 | 1 year ago |
|
|
970508fcb6 | 1 year ago |
|
|
9283a5414f | 1 year ago |
|
|
2a2a0e9be9 | 1 year ago |
|
|
061a765b7d | 1 year ago |
|
|
acd7fead87 | 1 year ago |
|
|
bbb080d5b2 | 1 year ago |
|
|
c01d8a70f3 | 1 year ago |
|
|
1ca15989e0 | 1 year ago |
|
|
8b5a3a9424 | 1 year ago |
|
|
42ddcf1edd | 1 year ago |
|
|
21561df10f | 1 year ago |
|
|
0e33a3aa5f | 1 year ago |
|
|
d3895bcd6b | 1 year ago |
|
|
eeb390650b | 1 year ago |
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"MD024": false,
|
||||||
|
"MD013": false
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to Dify will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.15.8] - 2025-05-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added gunicorn keepalive setting (#19537)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed database configuration to allow DB_EXTRAS to set search_path via options (#16a4f77)
|
||||||
|
- Fixed frontend third-party package security issues (#19655)
|
||||||
|
- Updated dependencies: huggingface-hub (~0.16.4 to ~0.31.0), transformers (~4.35.0 to ~4.39.0), and resend (~0.7.0 to ~2.9.0) (#19563)
|
||||||
|
- Downgrade boto3 from 1.36 to 1.35 (#19736)
|
||||||
|
|
||||||
|
## [0.15.7] - 2025-04-27
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for GPT-4.1 in model providers (#18912)
|
||||||
|
- Added support for Amazon Bedrock DeepSeek-R1 model (#18908)
|
||||||
|
- Added support for Amazon Bedrock Claude Sonnet 3.7 model (#18788)
|
||||||
|
- Refined version compatibility logic in app DSL service
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed issue with creating apps from template categories (#18807, #18868)
|
||||||
|
- Fixed DSL version check when creating apps from explore templates (#18872, #18878)
|
||||||
|
|
||||||
|
## [0.15.6] - 2025-04-22
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fixed clickjacking vulnerability (#18552)
|
||||||
|
- Fixed reset password security issue (#18366)
|
||||||
|
- Updated reset password token when email code verification succeeds (#18362)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed Vertex AI Gemini 2.0 Flash 001 schema (#18405)
|
||||||
@ -1,35 +0,0 @@
|
|||||||
model: gemini-pro-vision
|
|
||||||
label:
|
|
||||||
en_US: Gemini Pro Vision
|
|
||||||
model_type: llm
|
|
||||||
features:
|
|
||||||
- vision
|
|
||||||
model_properties:
|
|
||||||
mode: chat
|
|
||||||
context_size: 12288
|
|
||||||
parameter_rules:
|
|
||||||
- name: temperature
|
|
||||||
use_template: temperature
|
|
||||||
- name: top_p
|
|
||||||
use_template: top_p
|
|
||||||
- name: top_k
|
|
||||||
label:
|
|
||||||
zh_Hans: 取样数量
|
|
||||||
en_US: Top k
|
|
||||||
type: int
|
|
||||||
help:
|
|
||||||
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
|
|
||||||
en_US: Only sample from the top K options for each subsequent token.
|
|
||||||
required: false
|
|
||||||
- name: max_tokens_to_sample
|
|
||||||
use_template: max_tokens
|
|
||||||
required: true
|
|
||||||
default: 4096
|
|
||||||
min: 1
|
|
||||||
max: 4096
|
|
||||||
pricing:
|
|
||||||
input: '0.00'
|
|
||||||
output: '0.00'
|
|
||||||
unit: '0.000001'
|
|
||||||
currency: USD
|
|
||||||
deprecated: true
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
model: gemini-pro
|
|
||||||
label:
|
|
||||||
en_US: Gemini Pro
|
|
||||||
model_type: llm
|
|
||||||
features:
|
|
||||||
- agent-thought
|
|
||||||
- tool-call
|
|
||||||
- stream-tool-call
|
|
||||||
model_properties:
|
|
||||||
mode: chat
|
|
||||||
context_size: 30720
|
|
||||||
parameter_rules:
|
|
||||||
- name: temperature
|
|
||||||
use_template: temperature
|
|
||||||
- name: top_p
|
|
||||||
use_template: top_p
|
|
||||||
- name: top_k
|
|
||||||
label:
|
|
||||||
zh_Hans: 取样数量
|
|
||||||
en_US: Top k
|
|
||||||
type: int
|
|
||||||
help:
|
|
||||||
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
|
|
||||||
en_US: Only sample from the top K options for each subsequent token.
|
|
||||||
required: false
|
|
||||||
- name: max_tokens_to_sample
|
|
||||||
use_template: max_tokens
|
|
||||||
required: true
|
|
||||||
default: 2048
|
|
||||||
min: 1
|
|
||||||
max: 2048
|
|
||||||
- name: response_format
|
|
||||||
use_template: response_format
|
|
||||||
pricing:
|
|
||||||
input: '0.00'
|
|
||||||
output: '0.00'
|
|
||||||
unit: '0.000001'
|
|
||||||
currency: USD
|
|
||||||
deprecated: true
|
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
model: gpt-4.1
|
||||||
|
label:
|
||||||
|
zh_Hans: gpt-4.1
|
||||||
|
en_US: gpt-4.1
|
||||||
|
model_type: llm
|
||||||
|
features:
|
||||||
|
- multi-tool-call
|
||||||
|
- agent-thought
|
||||||
|
- stream-tool-call
|
||||||
|
- vision
|
||||||
|
model_properties:
|
||||||
|
mode: chat
|
||||||
|
context_size: 1047576
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: presence_penalty
|
||||||
|
use_template: presence_penalty
|
||||||
|
- name: frequency_penalty
|
||||||
|
use_template: frequency_penalty
|
||||||
|
- name: max_tokens
|
||||||
|
use_template: max_tokens
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 32768
|
||||||
|
- name: reasoning_effort
|
||||||
|
label:
|
||||||
|
zh_Hans: 推理工作
|
||||||
|
en_US: Reasoning Effort
|
||||||
|
type: string
|
||||||
|
help:
|
||||||
|
zh_Hans: 限制推理模型的推理工作
|
||||||
|
en_US: Constrains effort on reasoning for reasoning models
|
||||||
|
required: false
|
||||||
|
options:
|
||||||
|
- low
|
||||||
|
- medium
|
||||||
|
- high
|
||||||
|
- name: response_format
|
||||||
|
label:
|
||||||
|
zh_Hans: 回复格式
|
||||||
|
en_US: Response Format
|
||||||
|
type: string
|
||||||
|
help:
|
||||||
|
zh_Hans: 指定模型必须输出的格式
|
||||||
|
en_US: specifying the format that the model must output
|
||||||
|
required: false
|
||||||
|
options:
|
||||||
|
- text
|
||||||
|
- json_object
|
||||||
|
- json_schema
|
||||||
|
- name: json_schema
|
||||||
|
use_template: json_schema
|
||||||
|
pricing:
|
||||||
|
input: '2.00'
|
||||||
|
output: '8.00'
|
||||||
|
unit: '0.000001'
|
||||||
|
currency: USD
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
@ -1,46 +0,0 @@
|
|||||||
import re
|
|
||||||
from typing import Any
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from core.tools.errors import ToolProviderCredentialValidationError
|
|
||||||
from core.tools.provider.builtin.vanna.tools.vanna import VannaTool
|
|
||||||
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
|
|
||||||
|
|
||||||
|
|
||||||
class VannaProvider(BuiltinToolProviderController):
|
|
||||||
def _get_protocol_and_main_domain(self, url):
|
|
||||||
parsed_url = urlparse(url)
|
|
||||||
protocol = parsed_url.scheme
|
|
||||||
hostname = parsed_url.hostname
|
|
||||||
port = f":{parsed_url.port}" if parsed_url.port else ""
|
|
||||||
|
|
||||||
# Check if the hostname is an IP address
|
|
||||||
is_ip = re.match(r"^\d{1,3}(\.\d{1,3}){3}$", hostname) is not None
|
|
||||||
|
|
||||||
# Return the full hostname (with port if present) for IP addresses, otherwise return the main domain
|
|
||||||
main_domain = f"{hostname}{port}" if is_ip else ".".join(hostname.split(".")[-2:]) + port
|
|
||||||
return f"{protocol}://{main_domain}"
|
|
||||||
|
|
||||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
|
||||||
base_url = credentials.get("base_url")
|
|
||||||
if not base_url:
|
|
||||||
base_url = "https://ask.vanna.ai/rpc"
|
|
||||||
else:
|
|
||||||
base_url = base_url.removesuffix("/")
|
|
||||||
credentials["base_url"] = base_url
|
|
||||||
try:
|
|
||||||
VannaTool().fork_tool_runtime(
|
|
||||||
runtime={
|
|
||||||
"credentials": credentials,
|
|
||||||
}
|
|
||||||
).invoke(
|
|
||||||
user_id="",
|
|
||||||
tool_parameters={
|
|
||||||
"model": "chinook",
|
|
||||||
"db_type": "SQLite",
|
|
||||||
"url": f"{self._get_protocol_and_main_domain(credentials['base_url'])}/Chinook.sqlite",
|
|
||||||
"query": "What are the top 10 customers by sales?",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
raise ToolProviderCredentialValidationError(str(e))
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
identity:
|
|
||||||
author: QCTC
|
|
||||||
name: vanna
|
|
||||||
label:
|
|
||||||
en_US: Vanna.AI
|
|
||||||
zh_Hans: Vanna.AI
|
|
||||||
description:
|
|
||||||
en_US: The fastest way to get actionable insights from your database just by asking questions.
|
|
||||||
zh_Hans: 一个基于大模型和RAG的Text2SQL工具。
|
|
||||||
icon: icon.png
|
|
||||||
tags:
|
|
||||||
- utilities
|
|
||||||
- productivity
|
|
||||||
credentials_for_provider:
|
|
||||||
api_key:
|
|
||||||
type: secret-input
|
|
||||||
required: true
|
|
||||||
label:
|
|
||||||
en_US: API key
|
|
||||||
zh_Hans: API key
|
|
||||||
placeholder:
|
|
||||||
en_US: Please input your API key
|
|
||||||
zh_Hans: 请输入你的 API key
|
|
||||||
pt_BR: Please input your API key
|
|
||||||
help:
|
|
||||||
en_US: Get your API key from Vanna.AI
|
|
||||||
zh_Hans: 从 Vanna.AI 获取你的 API key
|
|
||||||
url: https://vanna.ai/account/profile
|
|
||||||
base_url:
|
|
||||||
type: text-input
|
|
||||||
required: false
|
|
||||||
label:
|
|
||||||
en_US: Vanna.AI Endpoint Base URL
|
|
||||||
placeholder:
|
|
||||||
en_US: https://ask.vanna.ai/rpc
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,46 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Modal from '@/app/components/base/modal'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
|
type DSLConfirmModalProps = {
|
||||||
|
versions?: {
|
||||||
|
importedVersion: string
|
||||||
|
systemVersion: string
|
||||||
|
}
|
||||||
|
onCancel: () => void
|
||||||
|
onConfirm: () => void
|
||||||
|
confirmDisabled?: boolean
|
||||||
|
}
|
||||||
|
const DSLConfirmModal = ({
|
||||||
|
versions = { importedVersion: '', systemVersion: '' },
|
||||||
|
onCancel,
|
||||||
|
onConfirm,
|
||||||
|
confirmDisabled = false,
|
||||||
|
}: DSLConfirmModalProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isShow
|
||||||
|
onClose={() => onCancel()}
|
||||||
|
className='w-[480px]'
|
||||||
|
>
|
||||||
|
<div className='flex flex-col items-start gap-2 self-stretch pb-4'>
|
||||||
|
<div className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
|
||||||
|
<div className='system-md-regular flex grow flex-col text-text-secondary'>
|
||||||
|
<div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
|
||||||
|
<div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
|
||||||
|
<br />
|
||||||
|
<div>{t('app.newApp.appCreateDSLErrorPart3')}<span className='system-md-medium'>{versions.importedVersion}</span></div>
|
||||||
|
<div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions.systemVersion}</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-start justify-end gap-2 self-stretch pt-6'>
|
||||||
|
<Button variant='secondary' onClick={() => onCancel()}>{t('app.newApp.Cancel')}</Button>
|
||||||
|
<Button variant='primary' destructive onClick={onConfirm} disabled={confirmDisabled}>{t('app.newApp.Confirm')}</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DSLConfirmModal
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
import {
|
||||||
|
useCallback,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import type {
|
||||||
|
DSLImportMode,
|
||||||
|
DSLImportResponse,
|
||||||
|
} from '@/models/app'
|
||||||
|
import { DSLImportStatus } from '@/models/app'
|
||||||
|
import {
|
||||||
|
importDSL,
|
||||||
|
importDSLConfirm,
|
||||||
|
} from '@/service/apps'
|
||||||
|
import type { AppIconType } from '@/types/app'
|
||||||
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
|
import { getRedirection } from '@/utils/app-redirection'
|
||||||
|
import { useSelector } from '@/context/app-context'
|
||||||
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||||
|
|
||||||
|
type DSLPayload = {
|
||||||
|
mode: DSLImportMode
|
||||||
|
yaml_content?: string
|
||||||
|
yaml_url?: string
|
||||||
|
name?: string
|
||||||
|
icon_type?: AppIconType
|
||||||
|
icon?: string
|
||||||
|
icon_background?: string
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
type ResponseCallback = {
|
||||||
|
onSuccess?: () => void
|
||||||
|
onPending?: (payload: DSLImportResponse) => void
|
||||||
|
onFailed?: () => void
|
||||||
|
}
|
||||||
|
export const useImportDSL = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { notify } = useToastContext()
|
||||||
|
const [isFetching, setIsFetching] = useState(false)
|
||||||
|
const isCurrentWorkspaceEditor = useSelector(s => s.isCurrentWorkspaceEditor)
|
||||||
|
const { push } = useRouter()
|
||||||
|
const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
|
||||||
|
const importIdRef = useRef<string>('')
|
||||||
|
|
||||||
|
const handleImportDSL = useCallback(async (
|
||||||
|
payload: DSLPayload,
|
||||||
|
{
|
||||||
|
onSuccess,
|
||||||
|
onPending,
|
||||||
|
onFailed,
|
||||||
|
}: ResponseCallback,
|
||||||
|
) => {
|
||||||
|
if (isFetching)
|
||||||
|
return
|
||||||
|
setIsFetching(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await importDSL(payload)
|
||||||
|
|
||||||
|
if (!response)
|
||||||
|
return
|
||||||
|
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
status,
|
||||||
|
app_id,
|
||||||
|
imported_dsl_version,
|
||||||
|
current_dsl_version,
|
||||||
|
} = response
|
||||||
|
|
||||||
|
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||||
|
if (!app_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
notify({
|
||||||
|
type: status === DSLImportStatus.COMPLETED ? 'success' : 'warning',
|
||||||
|
message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'),
|
||||||
|
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
|
||||||
|
})
|
||||||
|
onSuccess?.()
|
||||||
|
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||||
|
getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push)
|
||||||
|
}
|
||||||
|
else if (status === DSLImportStatus.PENDING) {
|
||||||
|
setVersions({
|
||||||
|
importedVersion: imported_dsl_version ?? '',
|
||||||
|
systemVersion: current_dsl_version ?? '',
|
||||||
|
})
|
||||||
|
importIdRef.current = id
|
||||||
|
onPending?.(response)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
|
onFailed?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
|
onFailed?.()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
setIsFetching(false)
|
||||||
|
}
|
||||||
|
}, [t, notify, isCurrentWorkspaceEditor, push, isFetching])
|
||||||
|
|
||||||
|
const handleImportDSLConfirm = useCallback(async (
|
||||||
|
{
|
||||||
|
onSuccess,
|
||||||
|
onFailed,
|
||||||
|
}: Pick<ResponseCallback, 'onSuccess' | 'onFailed'>,
|
||||||
|
) => {
|
||||||
|
if (isFetching)
|
||||||
|
return
|
||||||
|
setIsFetching(true)
|
||||||
|
if (!importIdRef.current)
|
||||||
|
return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await importDSLConfirm({
|
||||||
|
import_id: importIdRef.current,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { status, app_id } = response
|
||||||
|
if (!app_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (status === DSLImportStatus.COMPLETED) {
|
||||||
|
onSuccess?.()
|
||||||
|
notify({
|
||||||
|
type: 'success',
|
||||||
|
message: t('app.newApp.appCreated'),
|
||||||
|
})
|
||||||
|
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||||
|
getRedirection(isCurrentWorkspaceEditor, { id: app_id! }, push)
|
||||||
|
}
|
||||||
|
else if (status === DSLImportStatus.FAILED) {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
|
onFailed?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
|
onFailed?.()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
setIsFetching(false)
|
||||||
|
}
|
||||||
|
}, [t, notify, isCurrentWorkspaceEditor, push, isFetching])
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleImportDSL,
|
||||||
|
handleImportDSLConfirm,
|
||||||
|
versions,
|
||||||
|
isFetching,
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue