Compare commits
39 Commits
feat/knowl
...
v0.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 91d6cdb430 | |||
| 6ee7ccb019 | |||
| b7ada0cb6e | |||
| a1f3a9aead | |||
| f7d73cd391 | |||
| 5c5b40606a | |||
| 977f2c423a | |||
| 397912fccf | |||
| c4e0e27702 | |||
| 30fd1b3e27 | |||
| 71f6245a01 | |||
| 716ec0cba8 | |||
| 3f782d728f | |||
| 9660a85454 | |||
| 357da72a52 | |||
| 7ff025eef5 | |||
| 74f222c2e1 | |||
| 9b0c1cc235 | |||
| ae8403f867 | |||
| cacdba67cd | |||
| ce521dae8a | |||
| ab82507fd2 | |||
| bb74272385 | |||
| f93f26fc48 | |||
| 875e97a40d | |||
| b9d03b148c | |||
| 5013a9ed53 | |||
| efa20f22f6 | |||
| e3930873c6 | |||
| 2ed2a60479 | |||
| f589bb94bb | |||
| 02b4171576 | |||
| 0d83a5e7bc | |||
| 14ca189316 | |||
| 4310dee4c2 | |||
| 4ca3e597ff | |||
| 53345f58c2 | |||
| 8137b0aee5 | |||
| b48c4c2792 |
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@ -1,5 +1,8 @@
|
||||
* @Tecvan-fe @hi-pender @fanlv
|
||||
|
||||
/frontend/ @Tecvan-fe
|
||||
/common/ @Tecvan-fe
|
||||
|
||||
/frontend/apps/coze-studio/ @Tecvan-fe @evan-crash @duwenhan2byte
|
||||
/frontend/packages/agent-ide/agent-publish/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei @catee
|
||||
/frontend/packages/agent-ide/commons/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
@ -150,6 +153,7 @@
|
||||
/frontend/packages/studio/publish-manage-hooks/ @duwenhan2byte @evan-crash
|
||||
/frontend/packages/foundation/layout/ @evan-crash @duwenhan2byte
|
||||
/frontend/packages/studio/open-platform/open-auth/ @evan-crash @DingGao-Devin
|
||||
/frontend/packages/studio/open-platform/open-chat/ @tomasyu985 @DingGao-Devin
|
||||
/frontend/packages/agent-ide/entry-adapter/ @Hezi-crypto @duwenhan2byte @catee @evan-crash @haozhenfei
|
||||
/frontend/packages/agent-ide/entry/ @soonco @duwenhan2byte @catee @evan-crash
|
||||
/frontend/packages/agent-ide/bot-config-area-adapter/ @haozhenfei @Hezi-crypto @duwenhan2byte @catee @evan-crash
|
||||
@ -270,4 +274,4 @@
|
||||
|
||||
/backend/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
/docker/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
/helm/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
/helm/ @fanlv @junwen-lee @liuyunchao-1998 @lvxinyu-1117 @hi-pender @luohq-bytedance @shentongmartin @mrh997 @meguminnnnnnnnn @N3kox @zhuangjie1125
|
||||
|
||||
6
.github/scripts/check-file-size.sh
vendored
6
.github/scripts/check-file-size.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 设置默认值
|
||||
# Set default value
|
||||
TARGET_BRANCH=${targetBranch}
|
||||
CI_MODE=${CI:-false}
|
||||
|
||||
@ -36,11 +36,11 @@ else
|
||||
files=$(git diff --name-only --diff-filter=AM --cached $EXCLUDE_STRING)
|
||||
fi
|
||||
|
||||
# 体积限制为512KB
|
||||
# The volume limit is 512KB.
|
||||
size_limit=$((512))
|
||||
large_files_info=""
|
||||
|
||||
IFS=$'\n' # 处理文件名存在空格情况
|
||||
IFS=$'\n' # Handling the existence of spaces in the file name
|
||||
for file in $files; do
|
||||
file_size=$(wc -c <"$file" 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
|
||||
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
@ -37,10 +37,10 @@ jobs:
|
||||
- name: Process changed files
|
||||
id: process-files
|
||||
run: |
|
||||
# 获取所有变更文件
|
||||
# Get all change files
|
||||
all_files="${{ steps.changed-files.outputs.all_changed_files }}"
|
||||
|
||||
# 过滤掉 common/changes 目录下的文件
|
||||
# Filter out files in the common/changes directory
|
||||
filtered_files=""
|
||||
for file in $all_files; do
|
||||
if [[ ! "$file" =~ ^common/changes/.* ]]; then
|
||||
@ -52,10 +52,10 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
# 创建 JSON 格式的缓存文件
|
||||
# Create cached files in JSON format
|
||||
echo "[$( echo "$filtered_files" | sed 's/ /", "/g' | sed 's/^/"/' | sed 's/$/"/' )]" > changed-files-cache.json
|
||||
|
||||
# 输出缓存文件路径供后续步骤使用
|
||||
# Output cache file path for subsequent steps
|
||||
echo "cache_file=changed-files-cache.json" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "过滤前文件数量: $(echo $all_files | wc -w)"
|
||||
@ -163,12 +163,13 @@ jobs:
|
||||
- name: Increment Test:cov
|
||||
run: node common/scripts/install-run-rush.js increment --action test:cov -p "${{ needs.setup.outputs.cache_file }}"
|
||||
|
||||
- name: Upload coverage reports
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
# TODO: should resolve later
|
||||
# - name: Upload coverage reports
|
||||
# uses: codecov/codecov-action@v4
|
||||
# with:
|
||||
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||
# fail_ci_if_error: true
|
||||
# verbose: true
|
||||
|
||||
lint:
|
||||
needs: setup
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@ -6,6 +6,7 @@
|
||||
*.dylib
|
||||
|
||||
.env
|
||||
.env.debug
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
@ -32,7 +33,7 @@ output/*
|
||||
*.swp
|
||||
|
||||
# Vscode files
|
||||
.vscode
|
||||
.vscode/settings.json
|
||||
|
||||
/patches
|
||||
/oldimpl
|
||||
@ -52,3 +53,8 @@ common/temp
|
||||
|
||||
|
||||
backend/conf/model/*.yaml
|
||||
values-dev.yaml
|
||||
**/conf/model_ark_doubao-seed-1.6.yaml
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
|
||||
15
.vscode/extensions.json
vendored
Normal file
15
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"editorconfig.editorconfig",
|
||||
"esbenp.prettier-vscode",
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"codezombiech.gitignore",
|
||||
"aaron-bond.better-comments",
|
||||
"mikestead.dotenv",
|
||||
"stylelint.vscode-stylelint"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"nucllear.vscode-extension-auto-import",
|
||||
"steoates.autoimport"
|
||||
]
|
||||
}
|
||||
183
.vscode/settings.template.json
vendored
Normal file
183
.vscode/settings.template.json
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
{
|
||||
"eslint.nodePath": "frontend/config/eslint-config/node_modules/eslint",
|
||||
"prettier.prettierPath": "frontend/config/eslint-config/node_modules/prettier",
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": false,
|
||||
"editor.formatOnPaste": false,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "never",
|
||||
"source.fixAll.eslint": "never",
|
||||
"source.removeUnused": "never",
|
||||
"source.organizeImports": "never"
|
||||
// "source.sortImports": "always"
|
||||
},
|
||||
"editor.formatOnSaveMode": "modificationsIfAvailable",
|
||||
"search.followSymlinks": false,
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/.nyc_output": true,
|
||||
"**/.rush": true,
|
||||
"**/pnpm-lock.yaml": true,
|
||||
"**/CHANGELOG.json": true,
|
||||
"**/CHANGELOG.md": true,
|
||||
"common/changes": true,
|
||||
"**/output": true,
|
||||
"**/lib": true,
|
||||
"**/rush-logs": true,
|
||||
"**/dist": true,
|
||||
"**/coverage": true,
|
||||
"common/temp": true
|
||||
},
|
||||
"eslint.workingDirectories": [
|
||||
{
|
||||
"mode": "auto"
|
||||
}
|
||||
],
|
||||
"files.defaultLanguage": "plaintext",
|
||||
"files.associations": {
|
||||
".code-workspace": "jsonc",
|
||||
".babelrc": "json",
|
||||
".eslintrc": "jsonc",
|
||||
".eslintrc*.json": "jsonc",
|
||||
".stylelintrc": "javascript",
|
||||
"stylelintrc": "jsonc",
|
||||
"*.json": "jsonc",
|
||||
"package.json": "json",
|
||||
".htmlhintrc": "jsonc",
|
||||
"htmlhintrc": "jsonc",
|
||||
"Procfile*": "shellscript",
|
||||
"README": "markdown",
|
||||
"**/coverage/**/*.*": "plaintext",
|
||||
"OWNERS": "yaml",
|
||||
// Set the pnpm-lock file to plaintext to avoid parsing; otherwise, VSCode may freeze when opening the file
|
||||
"**/pnpm-lock.yaml": "plaintext",
|
||||
"**/dist/**": "plaintext",
|
||||
"**/dist_*/**": "plaintext",
|
||||
"*.map": "plaintext",
|
||||
"*.log": "plaintext"
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
"**/CVS": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/Thumbs.db": true,
|
||||
"**/.rush": true,
|
||||
"**/.swc": true
|
||||
},
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
"**/.git/subtree-cache/**": true,
|
||||
"**/node_modules/*/**": true
|
||||
},
|
||||
"search.useIgnoreFiles": true,
|
||||
//
|
||||
"editor.rulers": [80, 120],
|
||||
"files.eol": "\n",
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"cSpell.diagnosticLevel": "Warning",
|
||||
"eslint.probe": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
],
|
||||
"editor.semanticHighlighting.enabled": false,
|
||||
"eslint.format.enable": false,
|
||||
"eslint.enable": true,
|
||||
"eslint.useFlatConfig": true,
|
||||
"eslint.codeActionsOnSave.mode": "problems",
|
||||
"eslint.lintTask.enable": false,
|
||||
"javascript.validate.enable": false,
|
||||
"typescript.tsdk": "frontend/config/ts-config/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"typescript.disableAutomaticTypeAcquisition": true,
|
||||
"typescript.format.enable": false,
|
||||
"typescript.referencesCodeLens.enabled": false,
|
||||
"typescript.preferGoToSourceDefinition": true,
|
||||
"typescript.updateImportsOnFileMove.enabled": "never",
|
||||
// tsserver logs are not automatically deleted and accumulate over time, causing disk space issues, so disabled by default
|
||||
"typescript.tsserver.log": "off",
|
||||
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
|
||||
"typescript.workspaceSymbols.excludeLibrarySymbols": true,
|
||||
"editor.minimap.enabled": true,
|
||||
"typescript.preferences.includePackageJsonAutoImports": "off",
|
||||
"typescript.suggest.autoImports": true,
|
||||
"typescript.tsserver.maxTsServerMemory": 10240,
|
||||
"typescript.tsserver.enableRegionDiagnostics": false,
|
||||
"typescript.tsserver.watchOptions": {
|
||||
"fallbackPolling": "dynamicPriorityPolling",
|
||||
"synchronousWatchDirectory": true,
|
||||
"watchDirectory": "useFsEvents",
|
||||
"watchFile": "useFsEventsOnParentDirectory",
|
||||
"excludeDirectories": ["/**/node_modules"],
|
||||
"excludeLibrarySymbols": true,
|
||||
"excludeFiles": ["/**/node_modules/**"]
|
||||
},
|
||||
"css.validate": false,
|
||||
"scss.validate": false,
|
||||
"less.validate": false,
|
||||
"stylelint.enable": true,
|
||||
"stylelint.validate": ["css", "scss", "less"],
|
||||
"stylelint.stylelintPath": "frontend/config/stylelint-config/node_modules/stylelint",
|
||||
"emmet.triggerExpansionOnTab": true,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[html]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[less]": {
|
||||
"editor.defaultFormatter": "stylelint.vscode-stylelint"
|
||||
},
|
||||
"[scss]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[ignore]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[dotenv]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[svg]": {
|
||||
"editor.defaultFormatter": "jock.svg"
|
||||
},
|
||||
"svg.preview.background": "white",
|
||||
"[xml]": {
|
||||
"editor.defaultFormatter": "mblode.pretty-formatter"
|
||||
},
|
||||
"[sql]": {
|
||||
"editor.defaultFormatter": "adpyke.vscode-sql-formatter"
|
||||
},
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"references.preferredLocation": "view"
|
||||
}
|
||||
@ -28,7 +28,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
3. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the coze-dev {project_name} repo.
|
||||
4. In your forked repository, make your changes in a new git branch:
|
||||
```
|
||||
git checkout -b my-fix-branch develop
|
||||
git checkout -b my-fix-branch main
|
||||
```
|
||||
5. Create your patch, including appropriate test cases.
|
||||
6. Follow our [Style Guides](#code-style-guides).
|
||||
@ -38,7 +38,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
```
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
9. In GitHub, send a pull request to `{project_name}:develop`
|
||||
9. In GitHub, send a pull request to `{project_name}:main`
|
||||
|
||||
## Contribution Prerequisites
|
||||
- Our development environment keeps up with [Go Official](https://golang.org/project/).
|
||||
|
||||
18
Makefile
18
Makefile
@ -8,10 +8,10 @@ SYNC_DB_SCRIPT := $(SCRIPTS_DIR)/setup/db_migrate_apply.sh
|
||||
DUMP_DB_SCRIPT := $(SCRIPTS_DIR)/setup/db_migrate_dump.sh
|
||||
SETUP_DOCKER_SCRIPT := $(SCRIPTS_DIR)/setup/docker.sh
|
||||
SETUP_PYTHON_SCRIPT := $(SCRIPTS_DIR)/setup/python.sh
|
||||
COMPOSE_FILE := docker/docker-compose.yml
|
||||
COMPOSE_FILE := docker/docker-compose-debug.yml
|
||||
MYSQL_SCHEMA := ./docker/volumes/mysql/schema.sql
|
||||
MYSQL_INIT_SQL := ./docker/volumes/mysql/sql_init.sql
|
||||
ENV_FILE := ./docker/.env
|
||||
ENV_FILE := ./docker/.env.debug
|
||||
STATIC_DIR := ./bin/resources/static
|
||||
ES_INDEX_SCHEMA := ./docker/volumes/elasticsearch/es_index_schema
|
||||
ES_SETUP_SCRIPT := ./docker/volumes/elasticsearch/setup_es.sh
|
||||
@ -21,20 +21,20 @@ debug: env middleware python server
|
||||
env:
|
||||
@if [ ! -f "$(ENV_FILE)" ]; then \
|
||||
echo "Env file '$(ENV_FILE)' not found, using example env..."; \
|
||||
cp ./docker/.env.example $(ENV_FILE); \
|
||||
cp ./docker/.env.debug.example $(ENV_FILE); \
|
||||
fi
|
||||
|
||||
fe:
|
||||
@echo "Building frontend..."
|
||||
@bash $(BUILD_FE_SCRIPT)
|
||||
|
||||
server: env
|
||||
server: env setup_es_index
|
||||
@if [ ! -d "$(STATIC_DIR)" ]; then \
|
||||
echo "Static directory '$(STATIC_DIR)' not found, building frontend..."; \
|
||||
$(MAKE) fe; \
|
||||
fi
|
||||
@echo "Building and run server..."
|
||||
@bash $(BUILD_SERVER_SCRIPT) -start
|
||||
@APP_ENV=debug bash $(BUILD_SERVER_SCRIPT) -start
|
||||
|
||||
build_server:
|
||||
@echo "Building server..."
|
||||
@ -59,9 +59,9 @@ middleware:
|
||||
|
||||
web:
|
||||
@echo "Start web server in docker"
|
||||
@docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) --profile '*' up -d --wait
|
||||
@docker compose -f docker/docker-compose.yml up -d
|
||||
|
||||
down:
|
||||
down: env
|
||||
@echo "Stop all docker containers"
|
||||
@docker compose -f $(COMPOSE_FILE) --profile '*' down
|
||||
|
||||
@ -77,10 +77,10 @@ dump_sql_schema:
|
||||
@echo "Dumping mysql schema to $(MYSQL_SCHEMA)..."
|
||||
@. $(ENV_FILE); \
|
||||
{ echo "SET NAMES utf8mb4;\nCREATE DATABASE IF NOT EXISTS opencoze COLLATE utf8mb4_unicode_ci;"; atlas schema inspect -u $$ATLAS_URL --format "{{ sql . }}" --exclude "atlas_schema_revisions,table_*" | sed 's/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g'; } > $(MYSQL_SCHEMA)
|
||||
@sed -I '' -E 's/(\))[[:space:]]+CHARSET utf8mb4/\1 ENGINE=InnoDB CHARSET utf8mb4/' $(MYSQL_SCHEMA)
|
||||
@sed -i.bak -E 's/(\))[[:space:]]+CHARSET utf8mb4/\1 ENGINE=InnoDB CHARSET utf8mb4/' $(MYSQL_SCHEMA) && rm -f $(MYSQL_SCHEMA).bak
|
||||
@cat $(MYSQL_INIT_SQL) >> $(MYSQL_SCHEMA)
|
||||
@echo "Dumping mysql schema to helm/charts/opencoze/files/mysql ..."
|
||||
@cp $(MYSQL_SCHEMA) ./helm/charts/opencoze/files/mysql/
|
||||
@cp $(MYSQL_INIT_SQL) ./helm/charts/opencoze/files/mysql/
|
||||
|
||||
atlas-hash:
|
||||
@echo "Rehash atlas migration files..."
|
||||
|
||||
@ -72,9 +72,9 @@ Deployment steps:
|
||||
# Start the service
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
docker compose --profile "*" up -d
|
||||
docker compose up -d
|
||||
```
|
||||
After the service starts, it is normal for the `coze-minio-setup` , `coze-mysql-setup-init-sql` , and `coze-mysql-setup-schema` containers to be in an exited state (exit 0). For common startup failure issues, **please refer to the [FAQ](https://github.com/coze-dev/coze-studio/wiki/9.-FAQ)**.
|
||||
For common startup failure issues, **please refer to the [FAQ](https://github.com/coze-dev/coze-studio/wiki/9.-FAQ)**.
|
||||
4. After starting the service, you can open Coze Studio by accessing `http://localhost:8888/` through your browser.
|
||||
|
||||
|
||||
|
||||
@ -72,9 +72,9 @@ Coze Studio 的后端采用 Golang 开发,前端使用 React + TypeScript,
|
||||
# 启动服务
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
docker compose --profile "*" up -d
|
||||
docker compose up -d
|
||||
```
|
||||
服务启动之后`coze-minio-setup`、`coze-mysql-setup-init-sql`、`coze-mysql-setup-schema` 这几个容器处于退出状态(exit 0),是正常现象。**启动失败常见问题可参考[常见问题](https://github.com/coze-dev/coze-studio/wiki/9.-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)**。
|
||||
**启动失败常见问题可参考[常见问题](https://github.com/coze-dev/coze-studio/wiki/9.-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)**。
|
||||
|
||||
4. 启动服务后,通过浏览器访问 `http://localhost:8888/` 即可打开 Coze Studio。
|
||||
|
||||
|
||||
@ -10,12 +10,6 @@ RUN apk add --no-cache git gcc libc-dev
|
||||
COPY backend/go.mod backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
|
||||
COPY docker/proxy ./proxy
|
||||
|
||||
# Build the proxy application
|
||||
RUN go build -ldflags="-s -w" -o /app/proxy_app ./proxy/proxy.go
|
||||
|
||||
# Copy the entire backend source code
|
||||
COPY backend/ ./
|
||||
|
||||
@ -50,7 +44,6 @@ RUN apk add --no-cache --virtual .python-build-deps build-base py3-pip git && \
|
||||
|
||||
# Copy the built Go binary from the builder stage
|
||||
COPY --from=builder /app/opencoze /app/opencoze
|
||||
COPY --from=builder /app/proxy_app /app/proxy
|
||||
|
||||
# Copy Python application scripts
|
||||
COPY backend/infra/impl/document/parser/builtin/parse_pdf.py /app/parse_pdf.py
|
||||
@ -74,8 +67,6 @@ ENV PATH="/app/.venv/bin:${PATH}"
|
||||
RUN chmod +x /app/parse_pdf.py /app/parse_docx.py && \
|
||||
find /app/.venv/bin -type f -exec chmod +x {} \;
|
||||
|
||||
# Ensure Go binaries are executable
|
||||
RUN chmod +x /app/opencoze /app/proxy
|
||||
|
||||
EXPOSE 8888
|
||||
|
||||
|
||||
@ -239,7 +239,7 @@ func newWfTestRunner(t *testing.T) *wfTestRunner {
|
||||
|
||||
mockTos := storageMock.NewMockStorage(ctrl)
|
||||
mockTos.EXPECT().GetObjectUrl(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
|
||||
workflowRepo := service.NewWorkflowRepository(mockIDGen, db, redisClient, mockTos, cpStore)
|
||||
workflowRepo := service.NewWorkflowRepository(mockIDGen, db, redisClient, mockTos, cpStore, nil)
|
||||
mockey.Mock(appworkflow.GetWorkflowDomainSVC).Return(service.NewWorkflowService(workflowRepo)).Build()
|
||||
mockey.Mock(workflow2.GetRepository).Return(workflowRepo).Build()
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
)
|
||||
|
||||
@ -65,10 +66,6 @@ func (ot Openapi3T) Validate(ctx context.Context) (err error) {
|
||||
return errorx.New(errno.ErrPluginInvalidOpenapi3Doc, errorx.KVf(errno.PluginMsgKey,
|
||||
"invalid server url '%s'", serverURL))
|
||||
}
|
||||
if urlSchema.Scheme != "https" {
|
||||
return errorx.New(errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey,
|
||||
"server url must start with 'https://'"))
|
||||
}
|
||||
if urlSchema.Host == "" {
|
||||
return errorx.New(errno.ErrPluginInvalidOpenapi3Doc, errorx.KVf(errno.PluginMsgKey,
|
||||
"invalid server url '%s'", serverURL))
|
||||
|
||||
@ -263,6 +263,7 @@ func toAPIParameter(paramMeta paramMetaInfo, sc *openapi3.Schema) (*common.APIPa
|
||||
}
|
||||
|
||||
if sc.Default != nil {
|
||||
apiParam.GlobalDefault = ptr.Of(fmt.Sprintf("%v", sc.Default))
|
||||
apiParam.LocalDefault = ptr.Of(fmt.Sprintf("%v", sc.Default))
|
||||
}
|
||||
|
||||
|
||||
@ -190,8 +190,11 @@ func initPrimaryServices(ctx context.Context, basicServices *basicServices) (*pr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowDomainSVC := workflow.InitService(
|
||||
workflowDomainSVC, err := workflow.InitService(ctx,
|
||||
basicServices.toWorkflowServiceComponents(pluginSVC, memorySVC, knowledgeSVC))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shortcutSVC := shortcutcmd.InitService(basicServices.infra.DB, basicServices.infra.IDGenSVC)
|
||||
|
||||
|
||||
@ -20,9 +20,8 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
@ -33,14 +32,6 @@ import (
|
||||
func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (*openapi3.Operation, error) {
|
||||
op := &openapi3.Operation{}
|
||||
|
||||
if reqParams != nil && len(reqParams) == 0 {
|
||||
op.Parameters = []*openapi3.ParameterRef{}
|
||||
op.RequestBody = entity.DefaultOpenapi3RequestBody()
|
||||
}
|
||||
if respParams != nil && len(respParams) == 0 {
|
||||
op.Responses = entity.DefaultOpenapi3Responses()
|
||||
}
|
||||
|
||||
hasSetReqBody := false
|
||||
hasSetParams := false
|
||||
|
||||
@ -97,6 +88,15 @@ func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (
|
||||
}
|
||||
}
|
||||
|
||||
if reqParams != nil {
|
||||
if !hasSetParams {
|
||||
op.Parameters = []*openapi3.ParameterRef{}
|
||||
}
|
||||
if !hasSetReqBody {
|
||||
op.RequestBody = entity.DefaultOpenapi3RequestBody()
|
||||
}
|
||||
}
|
||||
|
||||
hasSetRespBody := false
|
||||
|
||||
for _, apiParam := range respParams {
|
||||
@ -136,6 +136,10 @@ func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (
|
||||
}
|
||||
}
|
||||
|
||||
if respParams != nil && !hasSetRespBody {
|
||||
op.Responses = entity.DefaultOpenapi3Responses()
|
||||
}
|
||||
|
||||
return op, nil
|
||||
}
|
||||
|
||||
|
||||
@ -455,7 +455,7 @@ func (c *ConversationApplicationService) parseMultiContent(ctx context.Context,
|
||||
mc[index].File.FileURL = resourceUrl
|
||||
|
||||
multiContents = append(multiContents, &crossDomainMessage.InputMetaData{
|
||||
Type: crossDomainMessage.InputType(item.Type),
|
||||
Type: c.getType(item.File.FileType),
|
||||
FileData: []*crossDomainMessage.FileData{
|
||||
{
|
||||
Url: resourceUrl,
|
||||
@ -468,10 +468,20 @@ func (c *ConversationApplicationService) parseMultiContent(ctx context.Context,
|
||||
|
||||
return multiContents, mc
|
||||
}
|
||||
func (c *ConversationApplicationService) getType(fileType string) crossDomainMessage.InputType {
|
||||
switch fileType {
|
||||
case string(crossDomainMessage.InputTypeAudio):
|
||||
return crossDomainMessage.InputTypeAudio
|
||||
case string(crossDomainMessage.InputTypeVideo):
|
||||
return crossDomainMessage.InputTypeVideo
|
||||
default:
|
||||
return crossDomainMessage.InputTypeFile
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConversationApplicationService) getUrlByUri(ctx context.Context, uri string) (string, error) {
|
||||
func (c *ConversationApplicationService) getUrlByUri(ctx context.Context, uri string) (string, error) {
|
||||
|
||||
url, err := s.appContext.ImageX.GetResourceURL(ctx, uri)
|
||||
url, err := c.appContext.ImageX.GetResourceURL(ctx, uri)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
109
backend/application/internal/env.go
Normal file
109
backend/application/internal/env.go
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
ao "github.com/cloudwego/eino-ext/components/model/ark"
|
||||
"github.com/cloudwego/eino-ext/components/model/deepseek"
|
||||
"github.com/cloudwego/eino-ext/components/model/gemini"
|
||||
"github.com/cloudwego/eino-ext/components/model/ollama"
|
||||
mo "github.com/cloudwego/eino-ext/components/model/openai"
|
||||
"github.com/cloudwego/eino-ext/components/model/qwen"
|
||||
"google.golang.org/genai"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
)
|
||||
|
||||
func GetBuiltinChatModel(ctx context.Context, envPrefix string) (bcm chatmodel.BaseChatModel, configured bool, err error) {
|
||||
getEnv := func(key string) string {
|
||||
if val := os.Getenv(envPrefix + key); val != "" {
|
||||
return val
|
||||
}
|
||||
return os.Getenv(key)
|
||||
}
|
||||
|
||||
switch getEnv("BUILTIN_CM_TYPE") {
|
||||
case "openai":
|
||||
byAzure, _ := strconv.ParseBool(getEnv("BUILTIN_CM_OPENAI_BY_AZURE"))
|
||||
bcm, err = mo.NewChatModel(ctx, &mo.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_OPENAI_API_KEY"),
|
||||
ByAzure: byAzure,
|
||||
BaseURL: getEnv("BUILTIN_CM_OPENAI_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_OPENAI_MODEL"),
|
||||
})
|
||||
case "ark":
|
||||
bcm, err = ao.NewChatModel(ctx, &ao.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_ARK_API_KEY"),
|
||||
Model: getEnv("BUILTIN_CM_ARK_MODEL"),
|
||||
BaseURL: getEnv("BUILTIN_CM_ARK_BASE_URL"),
|
||||
})
|
||||
case "deepseek":
|
||||
bcm, err = deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_DEEPSEEK_API_KEY"),
|
||||
BaseURL: getEnv("BUILTIN_CM_DEEPSEEK_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_DEEPSEEK_MODEL"),
|
||||
})
|
||||
case "ollama":
|
||||
bcm, err = ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
|
||||
BaseURL: getEnv("BUILTIN_CM_OLLAMA_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_OLLAMA_MODEL"),
|
||||
})
|
||||
case "qwen":
|
||||
bcm, err = qwen.NewChatModel(ctx, &qwen.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_QWEN_API_KEY"),
|
||||
BaseURL: getEnv("BUILTIN_CM_QWEN_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_QWEN_MODEL"),
|
||||
})
|
||||
case "gemini":
|
||||
backend, convErr := strconv.ParseInt(getEnv("BUILTIN_CM_GEMINI_BACKEND"), 10, 64)
|
||||
if convErr != nil {
|
||||
return nil, false, convErr
|
||||
}
|
||||
c, clientErr := genai.NewClient(ctx, &genai.ClientConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_GEMINI_API_KEY"),
|
||||
Backend: genai.Backend(backend),
|
||||
Project: getEnv("BUILTIN_CM_GEMINI_PROJECT"),
|
||||
Location: getEnv("BUILTIN_CM_GEMINI_LOCATION"),
|
||||
HTTPOptions: genai.HTTPOptions{
|
||||
BaseURL: getEnv("BUILTIN_CM_GEMINI_BASE_URL"),
|
||||
},
|
||||
})
|
||||
if clientErr != nil {
|
||||
return nil, false, clientErr
|
||||
}
|
||||
bcm, err = gemini.NewChatModel(ctx, &gemini.Config{
|
||||
Client: c,
|
||||
Model: getEnv("BUILTIN_CM_GEMINI_MODEL"),
|
||||
})
|
||||
default:
|
||||
// accept builtin chat model not configured
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("knowledge init openai chat mode failed, %w", err)
|
||||
}
|
||||
if bcm != nil {
|
||||
configured = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@ -28,24 +28,17 @@ import (
|
||||
"github.com/cloudwego/eino-ext/components/embedding/ark"
|
||||
ollamaEmb "github.com/cloudwego/eino-ext/components/embedding/ollama"
|
||||
"github.com/cloudwego/eino-ext/components/embedding/openai"
|
||||
ao "github.com/cloudwego/eino-ext/components/model/ark"
|
||||
"github.com/cloudwego/eino-ext/components/model/deepseek"
|
||||
"github.com/cloudwego/eino-ext/components/model/gemini"
|
||||
"github.com/cloudwego/eino-ext/components/model/ollama"
|
||||
mo "github.com/cloudwego/eino-ext/components/model/openai"
|
||||
"github.com/cloudwego/eino-ext/components/model/qwen"
|
||||
"github.com/cloudwego/eino/components/prompt"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/milvus-io/milvus/client/v2/milvusclient"
|
||||
"github.com/volcengine/volc-sdk-golang/service/vikingdb"
|
||||
"github.com/volcengine/volc-sdk-golang/service/visual"
|
||||
"google.golang.org/genai"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/application/internal"
|
||||
"github.com/coze-dev/coze-studio/backend/application/search"
|
||||
knowledgeImpl "github.com/coze-dev/coze-studio/backend/domain/knowledge/service"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/cache"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/nl2sql"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/ocr"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/searchstore"
|
||||
@ -65,6 +58,7 @@ import (
|
||||
ssmilvus "github.com/coze-dev/coze-studio/backend/infra/impl/document/searchstore/milvus"
|
||||
ssvikingdb "github.com/coze-dev/coze-studio/backend/infra/impl/document/searchstore/vikingdb"
|
||||
arkemb "github.com/coze-dev/coze-studio/backend/infra/impl/embedding/ark"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/embedding/http"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/embedding/wrap"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/eventbus"
|
||||
builtinM2Q "github.com/coze-dev/coze-studio/backend/infra/impl/messages2query/builtin"
|
||||
@ -130,7 +124,7 @@ func InitService(c *ServiceComponents) (*KnowledgeApplicationService, error) {
|
||||
}
|
||||
|
||||
var rewriter messages2query.MessagesToQuery
|
||||
if rewriterChatModel, _, err := getBuiltinChatModel(ctx, "M2Q_"); err != nil {
|
||||
if rewriterChatModel, _, err := internal.GetBuiltinChatModel(ctx, "M2Q_"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
filePath := filepath.Join(root, "resources/conf/prompt/messages_to_query_template_jinja2.json")
|
||||
@ -145,7 +139,7 @@ func InitService(c *ServiceComponents) (*KnowledgeApplicationService, error) {
|
||||
}
|
||||
|
||||
var n2s nl2sql.NL2SQL
|
||||
if n2sChatModel, _, err := getBuiltinChatModel(ctx, "NL2SQL_"); err != nil {
|
||||
if n2sChatModel, _, err := internal.GetBuiltinChatModel(ctx, "NL2SQL_"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
filePath := filepath.Join(root, "resources/conf/prompt/nl2sql_template_jinja2.json")
|
||||
@ -159,7 +153,7 @@ func InitService(c *ServiceComponents) (*KnowledgeApplicationService, error) {
|
||||
}
|
||||
}
|
||||
|
||||
imageAnnoChatModel, configured, err := getBuiltinChatModel(ctx, "IA_")
|
||||
imageAnnoChatModel, configured, err := internal.GetBuiltinChatModel(ctx, "IA_")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -286,6 +280,14 @@ func getVectorStore(ctx context.Context) (searchstore.Manager, error) {
|
||||
}
|
||||
|
||||
func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
var batchSize int
|
||||
if bs, err := strconv.ParseInt(os.Getenv("EMBEDDING_MAX_BATCH_SIZE"), 10, 64); err != nil {
|
||||
logs.CtxWarnf(ctx, "EMBEDDING_MAX_BATCH_SIZE not set / invalid, using default batchSize=100")
|
||||
batchSize = 100
|
||||
} else {
|
||||
batchSize = int(bs)
|
||||
}
|
||||
|
||||
var emb embedding.Embedder
|
||||
|
||||
switch os.Getenv("EMBEDDING_TYPE") {
|
||||
@ -324,7 +326,7 @@ func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
openAICfg.Dimensions = ptr.Of(int(reqDims))
|
||||
}
|
||||
|
||||
emb, err = wrap.NewOpenAIEmbedder(ctx, openAICfg, dims)
|
||||
emb, err = wrap.NewOpenAIEmbedder(ctx, openAICfg, dims, batchSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init openai embedding failed, err=%w", err)
|
||||
}
|
||||
@ -346,7 +348,7 @@ func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
APIKey: arkEmbeddingAK,
|
||||
Model: arkEmbeddingModel,
|
||||
BaseURL: arkEmbeddingBaseURL,
|
||||
}, dims)
|
||||
}, dims, batchSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init ark embedding client failed, err=%w", err)
|
||||
}
|
||||
@ -366,11 +368,25 @@ func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
emb, err = wrap.NewOllamaEmbedder(ctx, &ollamaEmb.EmbeddingConfig{
|
||||
BaseURL: ollamaEmbeddingBaseURL,
|
||||
Model: ollamaEmbeddingModel,
|
||||
}, dims)
|
||||
}, dims, batchSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init ollama embedding failed, err=%w", err)
|
||||
}
|
||||
|
||||
case "http":
|
||||
var (
|
||||
httpEmbeddingBaseURL = os.Getenv("HTTP_EMBEDDING_ADDR")
|
||||
httpEmbeddingDims = os.Getenv("HTTP_EMBEDDING_DIMS")
|
||||
)
|
||||
dims, err := strconv.ParseInt(httpEmbeddingDims, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init http embedding dims failed, err=%w", err)
|
||||
}
|
||||
emb, err = http.NewEmbedding(httpEmbeddingBaseURL, dims, batchSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init http embedding failed, err=%w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("init knowledge embedding failed, type not configured")
|
||||
}
|
||||
@ -378,81 +394,6 @@ func getEmbedding(ctx context.Context) (embedding.Embedder, error) {
|
||||
return emb, nil
|
||||
}
|
||||
|
||||
func getBuiltinChatModel(ctx context.Context, envPrefix string) (bcm chatmodel.BaseChatModel, configured bool, err error) {
|
||||
getEnv := func(key string) string {
|
||||
if val := os.Getenv(envPrefix + key); val != "" {
|
||||
return val
|
||||
}
|
||||
return os.Getenv(key)
|
||||
}
|
||||
|
||||
switch getEnv("BUILTIN_CM_TYPE") {
|
||||
case "openai":
|
||||
byAzure, _ := strconv.ParseBool(getEnv("BUILTIN_CM_OPENAI_BY_AZURE"))
|
||||
bcm, err = mo.NewChatModel(ctx, &mo.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_OPENAI_API_KEY"),
|
||||
ByAzure: byAzure,
|
||||
BaseURL: getEnv("BUILTIN_CM_OPENAI_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_OPENAI_MODEL"),
|
||||
})
|
||||
case "ark":
|
||||
bcm, err = ao.NewChatModel(ctx, &ao.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_ARK_API_KEY"),
|
||||
Model: getEnv("BUILTIN_CM_ARK_MODEL"),
|
||||
BaseURL: getEnv("BUILTIN_CM_ARK_BASE_URL"),
|
||||
})
|
||||
case "deepseek":
|
||||
bcm, err = deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_DEEPSEEK_API_KEY"),
|
||||
BaseURL: getEnv("BUILTIN_CM_DEEPSEEK_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_DEEPSEEK_MODEL"),
|
||||
})
|
||||
case "ollama":
|
||||
bcm, err = ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
|
||||
BaseURL: getEnv("BUILTIN_CM_OLLAMA_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_OLLAMA_MODEL"),
|
||||
})
|
||||
case "qwen":
|
||||
bcm, err = qwen.NewChatModel(ctx, &qwen.ChatModelConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_QWEN_API_KEY"),
|
||||
BaseURL: getEnv("BUILTIN_CM_QWEN_BASE_URL"),
|
||||
Model: getEnv("BUILTIN_CM_QWEN_MODEL"),
|
||||
})
|
||||
case "gemini":
|
||||
backend, convErr := strconv.ParseInt(getEnv("BUILTIN_CM_GEMINI_BACKEND"), 10, 64)
|
||||
if convErr != nil {
|
||||
return nil, false, convErr
|
||||
}
|
||||
c, clientErr := genai.NewClient(ctx, &genai.ClientConfig{
|
||||
APIKey: getEnv("BUILTIN_CM_GEMINI_API_KEY"),
|
||||
Backend: genai.Backend(backend),
|
||||
Project: getEnv("BUILTIN_CM_GEMINI_PROJECT"),
|
||||
Location: getEnv("BUILTIN_CM_GEMINI_LOCATION"),
|
||||
HTTPOptions: genai.HTTPOptions{
|
||||
BaseURL: getEnv("BUILTIN_CM_GEMINI_BASE_URL"),
|
||||
},
|
||||
})
|
||||
if clientErr != nil {
|
||||
return nil, false, clientErr
|
||||
}
|
||||
bcm, err = gemini.NewChatModel(ctx, &gemini.Config{
|
||||
Client: c,
|
||||
Model: getEnv("BUILTIN_CM_GEMINI_MODEL"),
|
||||
})
|
||||
default:
|
||||
// accept builtin chat model not configured
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("knowledge init openai chat mode failed, %w", err)
|
||||
}
|
||||
if bcm != nil {
|
||||
configured = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func readJinja2PromptTemplate(jsonFilePath string) (prompt.ChatTemplate, error) {
|
||||
b, err := os.ReadFile(jsonFilePath)
|
||||
if err != nil {
|
||||
|
||||
@ -106,7 +106,7 @@ func modelDo2To(model *modelmgr.Model, locale i18n.Locale) (*developer_api.Model
|
||||
PriceOut: 0,
|
||||
SystemPromptLimit: nil,
|
||||
},
|
||||
ModelName: mm.Name,
|
||||
ModelName: model.Name,
|
||||
ModelClassName: mm.Protocol.TOModelClass().String(),
|
||||
IsOffline: mm.Status != modelmgr.StatusInUse,
|
||||
ModelParams: mps,
|
||||
|
||||
@ -250,7 +250,7 @@ func (p *PluginApplicationService) RegisterPluginMeta(ctx context.Context, req *
|
||||
if req.GetLocation() == common.AuthorizationServiceLocation_Query {
|
||||
loc = model.ParamInQuery
|
||||
} else if req.GetLocation() == common.AuthorizationServiceLocation_Header {
|
||||
loc = model.ParamInPath
|
||||
loc = model.ParamInHeader
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid location '%s'", req.GetLocation())
|
||||
}
|
||||
@ -822,7 +822,7 @@ func (p *PluginApplicationService) UpdateAPI(ctx context.Context, req *pluginAPI
|
||||
method = &m
|
||||
}
|
||||
|
||||
updateReq := &service.UpdateToolDraftRequest{
|
||||
updateReq := &service.UpdateDraftToolRequest{
|
||||
PluginID: req.PluginID,
|
||||
ToolID: req.APIID,
|
||||
Name: req.Name,
|
||||
|
||||
@ -259,7 +259,7 @@ func toModelDetail(m *modelmgr.Model) *playground.ModelDetail {
|
||||
|
||||
return &playground.ModelDetail{
|
||||
Name: ptr.Of(m.Name),
|
||||
ModelName: ptr.Of(m.Meta.Name),
|
||||
ModelName: ptr.Of(m.Name),
|
||||
ModelID: ptr.Of(m.ID),
|
||||
ModelFamily: ptr.Of(int64(mm.Protocol.TOModelClass())),
|
||||
ModelIconURL: ptr.Of(m.IconURL),
|
||||
|
||||
@ -17,10 +17,15 @@
|
||||
package workflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/application/internal"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
|
||||
wfdatabase "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/database"
|
||||
wfknowledge "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/knowledge"
|
||||
wfmodel "github.com/coze-dev/coze-studio/backend/crossdomain/workflow/model"
|
||||
@ -64,9 +69,16 @@ type ServiceComponents struct {
|
||||
CodeRunner coderunner.Runner
|
||||
}
|
||||
|
||||
func InitService(components *ServiceComponents) *ApplicationService {
|
||||
func InitService(ctx context.Context, components *ServiceComponents) (*ApplicationService, error) {
|
||||
bcm, ok, err := internal.GetBuiltinChatModel(ctx, "WKR_")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
logs.CtxWarnf(ctx, "workflow builtin chat model for knowledge recall not configured")
|
||||
}
|
||||
workflowRepo := service.NewWorkflowRepository(components.IDGen, components.DB, components.Cache,
|
||||
components.Tos, components.CPStore)
|
||||
components.Tos, components.CPStore, bcm)
|
||||
workflow.SetRepository(workflowRepo)
|
||||
|
||||
workflowDomainSVC := service.NewWorkflowService(workflowRepo)
|
||||
@ -84,5 +96,5 @@ func InitService(components *ServiceComponents) *ApplicationService {
|
||||
SVC.TosClient = components.Tos
|
||||
SVC.IDGenerator = components.IDGen
|
||||
|
||||
return SVC
|
||||
return SVC, err
|
||||
}
|
||||
|
||||
@ -90,7 +90,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: Doubao
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -107,10 +106,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -118,16 +117,10 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: doubao-1.5-lite
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,10 +81,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -93,16 +92,10 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: doubao-1.5-pro-256k
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,10 +81,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -93,16 +92,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: doubao-1.5-pro-32k
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,10 +81,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -93,16 +92,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-1.5-thinking-pro
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -105,10 +104,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -116,16 +115,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-1.5-thinking-vision-pro
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -106,10 +105,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -117,16 +116,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-1.5-vision-lite
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: false
|
||||
@ -105,10 +104,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -116,16 +115,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-1.5-vision-pro
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -106,10 +105,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -117,16 +116,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-seed-1.6-flash
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -106,10 +105,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -117,16 +116,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-seed-1.6-thinking
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -106,10 +105,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -117,16 +116,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: doubao-seed-1.6
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -106,10 +105,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -117,16 +116,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: deepseek-r1-ve
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,10 +81,10 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -93,16 +92,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: deepseek-v3-ve
|
||||
protocol: ark
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,10 +81,10 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://ark.cn-beijing.volces.com/api/v3/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
model: "" # model_id / endpoint_id
|
||||
temperature: 0.1
|
||||
frequency_penalty: 0
|
||||
presence_penalty: 0
|
||||
@ -93,16 +92,11 @@ meta:
|
||||
top_p: 0.7
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark:
|
||||
region: ""
|
||||
access_key: ""
|
||||
secret_key: ""
|
||||
retry_times: null
|
||||
custom_header: {}
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -128,7 +128,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: test_model
|
||||
protocol: test_protocol
|
||||
capability:
|
||||
function_call: true
|
||||
@ -150,7 +149,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: https://localhost:1234/chat/completion
|
||||
base_url: https://localhost:1234/v1
|
||||
api_key: qweasdzxc
|
||||
timeout: 10s
|
||||
model: model_name
|
||||
@ -164,7 +163,7 @@ meta:
|
||||
- bye
|
||||
enable_thinking: false
|
||||
openai:
|
||||
by_azure: true
|
||||
by_azure: false
|
||||
api_version: "2024-10-21"
|
||||
response_format:
|
||||
type: text
|
||||
|
||||
@ -47,7 +47,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: Claude-3.5-Sonnet
|
||||
protocol: claude
|
||||
capability:
|
||||
function_call: true
|
||||
@ -64,7 +63,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://api.anthropic.com/v1/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
@ -75,16 +74,11 @@ meta:
|
||||
top_p: 1
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude:
|
||||
by_bedrock: false
|
||||
access_key: ""
|
||||
secret_access_key: ""
|
||||
session_token: ""
|
||||
region: ""
|
||||
ark: null
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -69,7 +69,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: DeepSeek-V3
|
||||
protocol: deepseek
|
||||
capability:
|
||||
function_call: false
|
||||
@ -85,7 +84,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://api.deepseek.com"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
@ -96,12 +95,7 @@ meta:
|
||||
top_p: 1
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark: null
|
||||
deepseek:
|
||||
response_format_type: text
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -88,7 +88,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: Gemini-2.5-Flash
|
||||
protocol: gemini
|
||||
capability:
|
||||
function_call: true
|
||||
@ -107,7 +106,7 @@ meta:
|
||||
reasoning: true
|
||||
prefill_response: true
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://generativelanguage.googleapis.com/"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: gemini-2.5-flash
|
||||
@ -118,11 +117,6 @@ meta:
|
||||
top_p: 1
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark: null
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini:
|
||||
backend: 0
|
||||
project: ""
|
||||
|
||||
@ -47,7 +47,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: Gemma-3
|
||||
protocol: ollama
|
||||
capability:
|
||||
function_call: true
|
||||
@ -63,7 +62,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "http://host.docker.internal:11434"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
@ -74,11 +73,5 @@ meta:
|
||||
top_p: 0.95
|
||||
top_k: 20
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark: null
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -128,7 +128,6 @@ default_parameters:
|
||||
zh: 输入及输出设置
|
||||
en: Input and output settings
|
||||
meta:
|
||||
name: GPT-4o
|
||||
protocol: openai
|
||||
capability:
|
||||
function_call: true
|
||||
@ -145,7 +144,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://api.openai.com/v1"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
@ -162,10 +161,5 @@ meta:
|
||||
response_format:
|
||||
type: text
|
||||
jsonschema: null
|
||||
claude: null
|
||||
ark: null
|
||||
deepseek: null
|
||||
qwen: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -66,7 +66,6 @@ default_parameters:
|
||||
zh: 生成多样性
|
||||
en: Generation diversity
|
||||
meta:
|
||||
name: Qwen3-32B
|
||||
protocol: qwen
|
||||
capability:
|
||||
function_call: true
|
||||
@ -82,7 +81,7 @@ meta:
|
||||
reasoning: false
|
||||
prefill_response: false
|
||||
conn_config:
|
||||
base_url: ""
|
||||
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
api_key: ""
|
||||
timeout: 0s
|
||||
model: ""
|
||||
@ -93,14 +92,9 @@ meta:
|
||||
top_p: 1
|
||||
top_k: 0
|
||||
stop: []
|
||||
openai: null
|
||||
claude: null
|
||||
ark: null
|
||||
deepseek: null
|
||||
qwen:
|
||||
response_format:
|
||||
type: text
|
||||
jsonschema: null
|
||||
gemini: null
|
||||
custom: {}
|
||||
status: 0
|
||||
|
||||
@ -163,7 +163,7 @@ func BuildAgent(ctx context.Context, conf *Config) (r *AgentRunner, err error) {
|
||||
isReActAgent = true
|
||||
requireCheckpoint = true
|
||||
if modelInfo.Meta.Capability != nil && !modelInfo.Meta.Capability.FunctionCall {
|
||||
return nil, fmt.Errorf("model %v does not support function call", modelInfo.Meta.Name)
|
||||
return nil, fmt.Errorf("model %v does not support function call", modelInfo.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,9 +21,10 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/cloudwego/eino/compose"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/bot_common"
|
||||
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crossplugin"
|
||||
|
||||
@ -300,7 +300,7 @@ func (dao *MessageDAO) buildModelContent(msgDO *entity.Message) (string, error)
|
||||
URL: contentData.FileData[0].Url,
|
||||
}
|
||||
case message.InputTypeAudio:
|
||||
one.Type = schema.ChatMessagePartTypeFileURL
|
||||
one.Type = schema.ChatMessagePartTypeAudioURL
|
||||
one.AudioURL = &schema.ChatMessageAudioURL{
|
||||
URL: contentData.FileData[0].Url,
|
||||
URI: contentData.FileData[0].URI,
|
||||
@ -309,10 +309,12 @@ func (dao *MessageDAO) buildModelContent(msgDO *entity.Message) (string, error)
|
||||
multiContent = append(multiContent, one)
|
||||
}
|
||||
if len(multiContent) > 0 {
|
||||
multiContent = append(multiContent, schema.ChatMessagePart{
|
||||
Type: schema.ChatMessagePartTypeText,
|
||||
Text: msgDO.Content,
|
||||
})
|
||||
if len(msgDO.Content) > 0 {
|
||||
multiContent = append(multiContent, schema.ChatMessagePart{
|
||||
Type: schema.ChatMessagePartTypeText,
|
||||
Text: msgDO.Content,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
modelContentObj.Content = msgDO.Content
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ func (suite *KnowledgeTestSuite) SetupSuite() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
emb, err := hembed.NewEmbedding(embEndpoint)
|
||||
emb, err := hembed.NewEmbedding(embEndpoint, 1024, 1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/mohae/deepcopy"
|
||||
"golang.org/x/mod/semver"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
@ -59,18 +60,26 @@ var (
|
||||
|
||||
func GetToolProduct(toolID int64) (*ToolInfo, bool) {
|
||||
ti, ok := toolProducts[toolID]
|
||||
return ti, ok
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
ti_ := deepcopy.Copy(ti).(*ToolInfo)
|
||||
|
||||
return ti_, true
|
||||
}
|
||||
|
||||
func MGetToolProducts(toolIDs []int64) []*ToolInfo {
|
||||
tools := make([]*ToolInfo, 0, len(toolIDs))
|
||||
for _, toolID := range toolIDs {
|
||||
ti, ok := toolProducts[toolID]
|
||||
ti, ok := GetToolProduct(toolID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
tools = append(tools, ti)
|
||||
}
|
||||
|
||||
return tools
|
||||
}
|
||||
|
||||
|
||||
@ -157,7 +157,6 @@ func NewDefaultPluginManifest() *PluginManifest {
|
||||
Value: "Coze/1.0",
|
||||
},
|
||||
},
|
||||
model.ParamInPath: {},
|
||||
model.ParamInQuery: {},
|
||||
},
|
||||
}
|
||||
|
||||
@ -20,7 +20,9 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
|
||||
@ -55,6 +57,26 @@ func (a agentToolDraftPO) ToDO() *entity.ToolInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) getSelected(opt *ToolSelectedOption) (selected []field.Expr) {
|
||||
if opt == nil {
|
||||
return selected
|
||||
}
|
||||
|
||||
table := at.query.AgentToolDraft
|
||||
|
||||
if opt.ToolID {
|
||||
selected = append(selected, table.ToolID)
|
||||
}
|
||||
if opt.ToolMethod {
|
||||
selected = append(selected, table.Method)
|
||||
}
|
||||
if opt.ToolSubURL {
|
||||
selected = append(selected, table.SubURL)
|
||||
}
|
||||
|
||||
return selected
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) Get(ctx context.Context, agentID, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
|
||||
table := at.query.AgentToolDraft
|
||||
tl, err := table.WithContext(ctx).
|
||||
@ -120,13 +142,14 @@ func (at *AgentToolDraftDAO) MGet(ctx context.Context, agentID int64, toolIDs []
|
||||
return tools, nil
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) GetAll(ctx context.Context, agentID int64) (tools []*entity.ToolInfo, err error) {
|
||||
func (at *AgentToolDraftDAO) GetAll(ctx context.Context, agentID int64, opt *ToolSelectedOption) (tools []*entity.ToolInfo, err error) {
|
||||
const limit = 20
|
||||
table := at.query.AgentToolDraft
|
||||
cursor := int64(0)
|
||||
|
||||
for {
|
||||
tls, err := table.WithContext(ctx).
|
||||
Select(at.getSelected(opt)...).
|
||||
Where(
|
||||
table.AgentID.Eq(agentID),
|
||||
table.ID.Gt(cursor),
|
||||
@ -171,6 +194,16 @@ func (at *AgentToolDraftDAO) UpdateWithToolName(ctx context.Context, agentID int
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, agentID int64, tools []*entity.ToolInfo) (err error) {
|
||||
return at.batchCreateWithTX(ctx, tx, agentID, tools, false)
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) BatchCreateIgnoreConflictWithTX(ctx context.Context, tx *query.QueryTx, agentID int64, tools []*entity.ToolInfo) (err error) {
|
||||
return at.batchCreateWithTX(ctx, tx, agentID, tools, true)
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) batchCreateWithTX(ctx context.Context, tx *query.QueryTx, agentID int64,
|
||||
tools []*entity.ToolInfo, ignoreConflict bool) (err error) {
|
||||
|
||||
tls := make([]*model.AgentToolDraft, 0, len(tools))
|
||||
for _, tl := range tools {
|
||||
id, err := at.idGen.GenID(ctx)
|
||||
@ -192,7 +225,13 @@ func (at *AgentToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.Qu
|
||||
}
|
||||
|
||||
table := tx.AgentToolDraft
|
||||
err = table.WithContext(ctx).CreateInBatches(tls, 20)
|
||||
|
||||
if ignoreConflict {
|
||||
err = table.WithContext(ctx).Clauses(clause.OnConflict{DoNothing: true}).
|
||||
CreateInBatches(tls, 20)
|
||||
} else {
|
||||
err = table.WithContext(ctx).CreateInBatches(tls, 20)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -200,27 +239,6 @@ func (at *AgentToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.Qu
|
||||
return nil
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) DeleteAll(ctx context.Context, agentID int64) (err error) {
|
||||
const limit = 20
|
||||
table := at.query.AgentToolDraft
|
||||
|
||||
for {
|
||||
info, err := table.WithContext(ctx).
|
||||
Where(table.AgentID.Eq(agentID)).
|
||||
Limit(limit).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.RowsAffected == 0 || info.RowsAffected < limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) GetAllPluginIDs(ctx context.Context, agentID int64) (pluginIDs []int64, err error) {
|
||||
const size = 100
|
||||
table := at.query.AgentToolDraft
|
||||
@ -254,22 +272,22 @@ func (at *AgentToolDraftDAO) GetAllPluginIDs(ctx context.Context, agentID int64)
|
||||
return slices.Unique(pluginIDs), nil
|
||||
}
|
||||
|
||||
func (at *AgentToolDraftDAO) DeleteAllWithTX(ctx context.Context, tx *query.QueryTx, agentID int64) (err error) {
|
||||
func (at *AgentToolDraftDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, agentID int64, toolIDs []int64) (err error) {
|
||||
const limit = 20
|
||||
table := tx.AgentToolDraft
|
||||
|
||||
for {
|
||||
info, err := table.WithContext(ctx).
|
||||
Where(table.AgentID.Eq(agentID)).
|
||||
chunks := slices.Chunks(toolIDs, limit)
|
||||
for _, chunk := range chunks {
|
||||
_, err = table.WithContext(ctx).
|
||||
Where(
|
||||
table.AgentID.Eq(agentID),
|
||||
table.ToolID.In(chunk...),
|
||||
).
|
||||
Limit(limit).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.RowsAffected == 0 || info.RowsAffected < limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -25,7 +25,7 @@ import (
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
pluginModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
@ -50,7 +50,7 @@ type PluginDraftDAO struct {
|
||||
type pluginDraftPO model.PluginDraft
|
||||
|
||||
func (p pluginDraftPO) ToDO() *entity.PluginInfo {
|
||||
return entity.NewPluginInfo(&plugin.PluginInfo{
|
||||
return entity.NewPluginInfo(&pluginModel.PluginInfo{
|
||||
ID: p.ID,
|
||||
SpaceID: p.SpaceID,
|
||||
DeveloperID: p.DeveloperID,
|
||||
@ -257,9 +257,12 @@ func (p *PluginDraftDAO) List(ctx context.Context, spaceID, appID int64, pageInf
|
||||
}
|
||||
|
||||
func (p *PluginDraftDAO) Update(ctx context.Context, plugin *entity.PluginInfo) (err error) {
|
||||
mf, err := plugin.Manifest.EncryptAuthPayload()
|
||||
if err != nil {
|
||||
return fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
|
||||
var mf *pluginModel.PluginManifest
|
||||
if plugin.Manifest != nil {
|
||||
mf, err = plugin.Manifest.EncryptAuthPayload()
|
||||
if err != nil {
|
||||
return fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
|
||||
}
|
||||
}
|
||||
|
||||
m := &model.PluginDraft{
|
||||
|
||||
@ -114,7 +114,6 @@ func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolI
|
||||
}
|
||||
|
||||
func (t *ToolDraftDAO) genToolID(ctx context.Context) (id int64, err error) {
|
||||
|
||||
retryTimes := 5
|
||||
|
||||
for i := 0; i < retryTimes; i++ {
|
||||
@ -123,11 +122,13 @@ func (t *ToolDraftDAO) genToolID(ctx context.Context) (id int64, err error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, ok := conf.GetToolProduct(id); !ok {
|
||||
_, ok := conf.GetToolProduct(id)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if i == retryTimes-1 {
|
||||
return 0, fmt.Errorf("id %d is confilict with product tool id.", id)
|
||||
return 0, fmt.Errorf("id %d is confilict with product tool id", id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -946,14 +946,10 @@ func fillManifestWithOpenapiDoc(mf *entity.PluginManifest, doc *model.Openapi3T)
|
||||
}
|
||||
|
||||
func addHTTPProtocolHeadIfNeed(url string) string {
|
||||
if strings.HasPrefix(url, "https://") {
|
||||
if strings.HasPrefix(url, "https://") || strings.HasPrefix(url, "http://") {
|
||||
return url
|
||||
}
|
||||
if strings.HasPrefix(url, "http://") {
|
||||
url = strings.Replace(url, "http://", "https://", 1)
|
||||
return url
|
||||
}
|
||||
return "https://" + url
|
||||
return "http://" + url
|
||||
}
|
||||
|
||||
func fillNecessaryInfoForOpenapi3Doc(doc *model.Openapi3T) {
|
||||
|
||||
@ -853,3 +853,11 @@ func (p *pluginRepoImpl) MoveAPPPluginToLibrary(ctx context.Context, draftPlugin
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pluginRepoImpl) UpdateDebugExample(ctx context.Context, pluginID int64, openapiDoc *model.Openapi3T) (err error) {
|
||||
updatedPlugin := entity.NewPluginInfo(&model.PluginInfo{
|
||||
ID: pluginID,
|
||||
OpenapiDoc: openapiDoc,
|
||||
})
|
||||
return p.pluginDraftDAO.Update(ctx, updatedPlugin)
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ type PluginRepository interface {
|
||||
UpdateDraftPluginWithCode(ctx context.Context, req *UpdatePluginDraftWithCode) (err error)
|
||||
DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error)
|
||||
DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error)
|
||||
UpdateDebugExample(ctx context.Context, pluginID int64, openapiDoc *plugin.Openapi3T) (err error)
|
||||
|
||||
GetOnlinePlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error)
|
||||
MGetOnlinePlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error)
|
||||
|
||||
@ -23,7 +23,6 @@ import (
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal"
|
||||
@ -217,6 +216,7 @@ func (t *toolRepoImpl) GetOnlineTool(ctx context.Context, toolID int64) (tool *e
|
||||
|
||||
func (t *toolRepoImpl) MGetOnlineTools(ctx context.Context, toolIDs []int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error) {
|
||||
toolProducts := pluginConf.MGetToolProducts(toolIDs)
|
||||
|
||||
tools = slices.Transform(toolProducts, func(tool *pluginConf.ToolInfo) *entity.ToolInfo {
|
||||
return tool.Info
|
||||
})
|
||||
@ -270,13 +270,38 @@ func (t *toolRepoImpl) MGetVersionTools(ctx context.Context, versionTools []enti
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) BindDraftAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error) {
|
||||
onlineTools, err := t.MGetOnlineTools(ctx, toolIDs)
|
||||
opt := &dal.ToolSelectedOption{
|
||||
ToolID: true,
|
||||
}
|
||||
draftAgentTools, err := t.agentToolDraftDAO.GetAll(ctx, agentID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(onlineTools) == 0 {
|
||||
return t.agentToolDraftDAO.DeleteAll(ctx, agentID)
|
||||
draftAgentToolIDMap := slices.ToMap(draftAgentTools, func(tool *entity.ToolInfo) (int64, bool) {
|
||||
return tool.ID, true
|
||||
})
|
||||
|
||||
bindToolIDMap := slices.ToMap(toolIDs, func(toolID int64) (int64, bool) {
|
||||
return toolID, true
|
||||
})
|
||||
|
||||
newBindToolIDs := make([]int64, 0, len(toolIDs))
|
||||
for _, toolID := range toolIDs {
|
||||
_, ok := draftAgentToolIDMap[toolID]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
newBindToolIDs = append(newBindToolIDs, toolID)
|
||||
}
|
||||
|
||||
removeToolIDs := make([]int64, 0, len(draftAgentTools))
|
||||
for toolID := range draftAgentToolIDMap {
|
||||
_, ok := bindToolIDMap[toolID]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
removeToolIDs = append(removeToolIDs, toolID)
|
||||
}
|
||||
|
||||
tx := t.query.Begin()
|
||||
@ -299,17 +324,29 @@ func (t *toolRepoImpl) BindDraftAgentTools(ctx context.Context, agentID int64, t
|
||||
}
|
||||
}()
|
||||
|
||||
err = t.agentToolDraftDAO.DeleteAllWithTX(ctx, tx, agentID)
|
||||
onlineTools, err := t.MGetOnlineTools(ctx, newBindToolIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = t.agentToolDraftDAO.BatchCreateWithTX(ctx, tx, agentID, onlineTools)
|
||||
if len(onlineTools) > 0 {
|
||||
err = t.agentToolDraftDAO.BatchCreateIgnoreConflictWithTX(ctx, tx, agentID, onlineTools)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = t.agentToolDraftDAO.DeleteWithTX(ctx, tx, agentID, removeToolIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) GetAgentPluginIDs(ctx context.Context, agentID int64) (pluginIDs []int64, err error) {
|
||||
@ -317,7 +354,7 @@ func (t *toolRepoImpl) GetAgentPluginIDs(ctx context.Context, agentID int64) (pl
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error) {
|
||||
tools, err := t.agentToolDraftDAO.GetAll(ctx, fromAgentID)
|
||||
tools, err := t.agentToolDraftDAO.GetAll(ctx, fromAgentID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -371,7 +408,7 @@ func (t *toolRepoImpl) UpdateDraftAgentTool(ctx context.Context, req *UpdateDraf
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) GetSpaceAllDraftAgentTools(ctx context.Context, agentID int64) (tools []*entity.ToolInfo, err error) {
|
||||
return t.agentToolDraftDAO.GetAll(ctx, agentID)
|
||||
return t.agentToolDraftDAO.GetAll(ctx, agentID, nil)
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) GetVersionAgentTool(ctx context.Context, agentID int64, vAgentTool entity.VersionAgentTool) (tool *entity.ToolInfo, exist bool, err error) {
|
||||
@ -389,41 +426,3 @@ func (t *toolRepoImpl) MGetVersionAgentTool(ctx context.Context, agentID int64,
|
||||
func (t *toolRepoImpl) BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error) {
|
||||
return t.agentToolVersionDAO.BatchCreate(ctx, agentID, agentVersion, tools)
|
||||
}
|
||||
|
||||
func (t *toolRepoImpl) UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error) {
|
||||
tx := t.query.Begin()
|
||||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e := tx.Rollback(); e != nil {
|
||||
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
|
||||
}
|
||||
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
if e := tx.Rollback(); e != nil {
|
||||
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = t.toolDraftDAO.UpdateWithTX(ctx, tx, updatedTool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updatedPlugin := entity.NewPluginInfo(&plugin.PluginInfo{
|
||||
ID: pluginID,
|
||||
OpenapiDoc: doc,
|
||||
})
|
||||
err = t.pluginDraftDAO.UpdateWithTX(ctx, tx, updatedPlugin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
||||
)
|
||||
|
||||
@ -54,8 +53,6 @@ type ToolRepository interface {
|
||||
MGetVersionAgentTool(ctx context.Context, agentID int64, vAgentTools []entity.VersionAgentTool) (tools []*entity.ToolInfo, err error)
|
||||
BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error)
|
||||
|
||||
UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error)
|
||||
|
||||
GetPluginAllDraftTools(ctx context.Context, pluginID int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error)
|
||||
GetPluginAllOnlineTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error)
|
||||
ListPluginDraftTools(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (tools []*entity.ToolInfo, total int64, err error)
|
||||
|
||||
@ -29,6 +29,7 @@ import (
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
einoCompose "github.com/cloudwego/eino/compose"
|
||||
|
||||
@ -479,11 +480,6 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestStr, err := sonic.MarshalString(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err := t.buildHTTPRequest(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -504,18 +500,29 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
}
|
||||
|
||||
var reqBodyBytes []byte
|
||||
if httpReq.Body != nil {
|
||||
reqBodyBytes, err = io.ReadAll(httpReq.Body)
|
||||
if httpReq.GetBody != nil {
|
||||
reqBody, err := httpReq.GetBody()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer reqBody.Close()
|
||||
|
||||
reqBodyBytes, err = io.ReadAll(reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
requestStr, err := genRequestString(httpReq, reqBodyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restyReq := t.svc.httpCli.NewRequest()
|
||||
restyReq.Header = httpReq.Header
|
||||
restyReq.Method = httpReq.Method
|
||||
restyReq.URL = httpReq.URL.String()
|
||||
if len(reqBodyBytes) > 0 {
|
||||
if reqBodyBytes != nil {
|
||||
restyReq.SetBody(reqBodyBytes)
|
||||
}
|
||||
restyReq.SetContext(ctx)
|
||||
@ -559,6 +566,46 @@ func (t *toolExecutor) execute(ctx context.Context, argumentsInJson string) (res
|
||||
}, nil
|
||||
}
|
||||
|
||||
func genRequestString(req *http.Request, body []byte) (string, error) {
|
||||
type Request struct {
|
||||
Path string `json:"path"`
|
||||
Header map[string]string `json:"header"`
|
||||
Query map[string]string `json:"query"`
|
||||
Body *[]byte `json:"body"`
|
||||
}
|
||||
|
||||
req_ := &Request{
|
||||
Path: req.URL.Path,
|
||||
Header: map[string]string{},
|
||||
Query: map[string]string{},
|
||||
}
|
||||
|
||||
if len(req.Header) > 0 {
|
||||
for k, v := range req.Header {
|
||||
req_.Header[k] = v[0]
|
||||
}
|
||||
}
|
||||
if len(req.URL.Query()) > 0 {
|
||||
for k, v := range req.URL.Query() {
|
||||
req_.Query[k] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
requestStr, err := sonic.MarshalString(req_)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[genRequestString] marshal failed, err=%s", err)
|
||||
}
|
||||
|
||||
if len(body) > 0 {
|
||||
requestStr, err = sjson.SetRaw(requestStr, "body", string(body))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[genRequestString] set body failed, err=%s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return requestStr, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) preprocessArgumentsInJson(ctx context.Context, argumentsInJson string) (args map[string]any, err error) {
|
||||
args, err = t.prepareArguments(ctx, argumentsInJson)
|
||||
if err != nil {
|
||||
@ -653,23 +700,13 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqURL, err := locArgs.buildHTTPRequestURL(ctx, rawURL)
|
||||
commonParams := t.plugin.Manifest.CommonParams
|
||||
|
||||
reqURL, err := locArgs.buildHTTPRequestURL(ctx, rawURL, commonParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err = http.NewRequestWithContext(ctx, tool.GetMethod(), reqURL.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header, err := locArgs.buildHTTPRequestHeader(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq.Header = header
|
||||
|
||||
bodyArgs := map[string]any{}
|
||||
for k, v := range argMaps {
|
||||
if _, ok := locArgs.header[k]; ok {
|
||||
@ -684,13 +721,27 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
bodyArgs[k] = v
|
||||
}
|
||||
|
||||
bodyBytes, contentType, err := t.buildRequestBody(ctx, tool.Operation, bodyArgs)
|
||||
commonBody := commonParams[model.ParamInBody]
|
||||
bodyBytes, contentType, err := t.buildRequestBody(ctx, tool.Operation, bodyArgs, commonBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err = http.NewRequestWithContext(ctx, tool.GetMethod(), reqURL.String(), bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonHeader := commonParams[model.ParamInHeader]
|
||||
header, err := locArgs.buildHTTPRequestHeader(ctx, commonHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq.Header = header
|
||||
|
||||
if len(bodyBytes) > 0 {
|
||||
httpReq.Header.Set("Content-Type", contentType)
|
||||
httpReq.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
}
|
||||
|
||||
return httpReq, nil
|
||||
@ -698,13 +749,6 @@ func (t *toolExecutor) buildHTTPRequest(ctx context.Context, argMaps map[string]
|
||||
|
||||
func (t *toolExecutor) prepareArguments(_ context.Context, argumentsInJson string) (map[string]any, error) {
|
||||
args := map[string]any{}
|
||||
for loc, params := range t.plugin.Manifest.CommonParams {
|
||||
for _, p := range params {
|
||||
if loc != model.ParamInBody {
|
||||
args[p.Name] = p.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(argumentsInJson))
|
||||
decoder.UseNumber()
|
||||
@ -1175,7 +1219,9 @@ type valueWithSchema struct {
|
||||
paramSchema *openapi3.Parameter
|
||||
}
|
||||
|
||||
func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string) (reqURL *url.URL, err error) {
|
||||
func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string,
|
||||
commonParams map[model.HTTPParamLocation][]*common.CommonParamSchema) (reqURL *url.URL, err error) {
|
||||
|
||||
if len(l.path) > 0 {
|
||||
for k, v := range l.path {
|
||||
vStr, err := encoder.EncodeParameter(v.paramSchema, v.argValue)
|
||||
@ -1186,9 +1232,8 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
}
|
||||
}
|
||||
|
||||
encodeQuery := ""
|
||||
query := url.Values{}
|
||||
if len(l.query) > 0 {
|
||||
query := url.Values{}
|
||||
for k, val := range l.query {
|
||||
switch v := val.argValue.(type) {
|
||||
case []any:
|
||||
@ -1199,10 +1244,18 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
query.Add(k, encoder.MustString(v))
|
||||
}
|
||||
}
|
||||
|
||||
encodeQuery = query.Encode()
|
||||
}
|
||||
|
||||
commonQuery := commonParams[model.ParamInQuery]
|
||||
for _, v := range commonQuery {
|
||||
if _, ok := l.query[v.Name]; ok {
|
||||
continue
|
||||
}
|
||||
query.Add(v.Name, v.Value)
|
||||
}
|
||||
|
||||
encodeQuery := query.Encode()
|
||||
|
||||
reqURL, err = url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1217,7 +1270,7 @@ func (l *locationArguments) buildHTTPRequestURL(_ context.Context, rawURL string
|
||||
return reqURL, nil
|
||||
}
|
||||
|
||||
func (l *locationArguments) buildHTTPRequestHeader(_ context.Context) (http.Header, error) {
|
||||
func (l *locationArguments) buildHTTPRequestHeader(_ context.Context, commonHeaders []*common.CommonParamSchema) (http.Header, error) {
|
||||
header := http.Header{}
|
||||
if len(l.header) > 0 {
|
||||
for k, v := range l.header {
|
||||
@ -1232,44 +1285,64 @@ func (l *locationArguments) buildHTTPRequestHeader(_ context.Context) (http.Head
|
||||
}
|
||||
}
|
||||
|
||||
for _, h := range commonHeaders {
|
||||
if header.Get(h.Name) != "" {
|
||||
continue
|
||||
}
|
||||
header.Add(h.Name, h.Value)
|
||||
}
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) buildRequestBody(ctx context.Context, op *model.Openapi3Operation, bodyArgs map[string]any) (body []byte, contentType string, err error) {
|
||||
func (t *toolExecutor) buildRequestBody(ctx context.Context, op *model.Openapi3Operation, bodyArgs map[string]any,
|
||||
commonBody []*common.CommonParamSchema) (body []byte, contentType string, err error) {
|
||||
|
||||
var bodyMap map[string]any
|
||||
|
||||
contentType, bodySchema := t.getReqBodySchema(op)
|
||||
if bodySchema == nil || bodySchema.Value == nil {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
if len(bodySchema.Value.Properties) == 0 {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
bodyMap, err := t.injectRequestBodyDefaultValue(ctx, bodySchema.Value, bodyArgs)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
for paramName, prop := range bodySchema.Value.Properties {
|
||||
value, ok := bodyMap[paramName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_value, err := encoder.TryFixValueType(paramName, prop, value)
|
||||
if bodySchema != nil && len(bodySchema.Value.Properties) > 0 {
|
||||
bodyMap, err = t.injectRequestBodyDefaultValue(ctx, bodySchema.Value, bodyArgs)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
bodyMap[paramName] = _value
|
||||
for paramName, prop := range bodySchema.Value.Properties {
|
||||
value, ok := bodyMap[paramName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_value, err := encoder.TryFixValueType(paramName, prop, value)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
bodyMap[paramName] = _value
|
||||
}
|
||||
|
||||
body, err = encoder.EncodeBodyWithContentType(contentType, bodyMap)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] EncodeBodyWithContentType failed, err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
reqBodyStr, err := encoder.EncodeBodyWithContentType(contentType, bodyMap)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] EncodeBodyWithContentType failed, err=%v", err)
|
||||
commonBody_ := make([]*common.CommonParamSchema, 0, len(commonBody))
|
||||
for _, v := range commonBody {
|
||||
if _, ok := bodyMap[v.Name]; ok {
|
||||
continue
|
||||
}
|
||||
commonBody_ = append(commonBody_, v)
|
||||
}
|
||||
|
||||
return reqBodyStr, contentType, nil
|
||||
for _, v := range commonBody_ {
|
||||
body, err = sjson.SetRawBytes(body, v.Name, []byte(v.Value))
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("[buildRequestBody] SetRawBytes failed, err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return body, contentType, nil
|
||||
}
|
||||
|
||||
func (t *toolExecutor) injectRequestBodyDefaultValue(ctx context.Context, sc *openapi3.Schema, vals map[string]any) (newVals map[string]any, err error) {
|
||||
@ -1327,7 +1400,7 @@ func (t *toolExecutor) injectRequestBodyDefaultValue(ctx context.Context, sc *op
|
||||
}
|
||||
|
||||
func (t *toolExecutor) getReqBodySchema(op *model.Openapi3Operation) (string, *openapi3.SchemaRef) {
|
||||
if op.RequestBody == nil || op.RequestBody.Value == nil || len(op.RequestBody.Value.Content) == 0 {
|
||||
if op.RequestBody == nil || len(op.RequestBody.Value.Content) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
|
||||
49
backend/domain/plugin/service/exec_tool_test.go
Normal file
49
backend/domain/plugin/service/exec_tool_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
. "github.com/bytedance/mockey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenRequestString(t *testing.T) {
|
||||
PatchConvey("", t, func() {
|
||||
requestStr, err := genRequestString(&http.Request{
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
},
|
||||
Method: http.MethodPost,
|
||||
URL: &url.URL{Path: "/test"},
|
||||
}, []byte(`{"a": 1}`))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `{"header":{"Content-Type":["application/json"]},"query":null,"path":"/test","body":{"a": 1}}`, requestStr)
|
||||
})
|
||||
|
||||
PatchConvey("", t, func() {
|
||||
var body []byte
|
||||
requestStr, err := genRequestString(&http.Request{
|
||||
URL: &url.URL{Path: "/test"},
|
||||
}, body)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `{"header":null,"query":null,"path":"/test","body":null}`, requestStr)
|
||||
})
|
||||
}
|
||||
@ -46,6 +46,7 @@ import (
|
||||
|
||||
func (p *pluginServiceImpl) CreateDraftPlugin(ctx context.Context, req *CreateDraftPluginRequest) (pluginID int64, err error) {
|
||||
mf := entity.NewDefaultPluginManifest()
|
||||
mf.CommonParams = map[model.HTTPParamLocation][]*plugin_develop_common.CommonParamSchema{}
|
||||
mf.NameForHuman = req.Name
|
||||
mf.NameForModel = req.Name
|
||||
mf.DescriptionForHuman = req.Desc
|
||||
@ -65,11 +66,11 @@ func (p *pluginServiceImpl) CreateDraftPlugin(ctx context.Context, req *CreateDr
|
||||
return 0, fmt.Errorf("invalid location '%s'", loc.String())
|
||||
}
|
||||
for _, param := range params {
|
||||
mParams := mf.CommonParams[location]
|
||||
mParams = append(mParams, &plugin_develop_common.CommonParamSchema{
|
||||
Name: param.Name,
|
||||
Value: param.Value,
|
||||
})
|
||||
mf.CommonParams[location] = append(mf.CommonParams[location],
|
||||
&plugin_develop_common.CommonParamSchema{
|
||||
Name: param.Name,
|
||||
Value: param.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -577,7 +578,7 @@ func (p *pluginServiceImpl) MGetDraftTools(ctx context.Context, toolIDs []int64)
|
||||
return tools, nil
|
||||
}
|
||||
|
||||
func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error) {
|
||||
func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateDraftToolRequest) (err error) {
|
||||
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID)
|
||||
if err != nil {
|
||||
return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID)
|
||||
@ -594,6 +595,14 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
return errorx.New(errno.ErrPluginRecordNotFound)
|
||||
}
|
||||
|
||||
if req.SaveExample != nil {
|
||||
return p.updateDraftToolDebugExample(ctx, draftPlugin, draftTool, *req.SaveExample, req.DebugExample)
|
||||
}
|
||||
|
||||
return p.updateDraftTool(ctx, req, draftTool)
|
||||
}
|
||||
|
||||
func (p *pluginServiceImpl) updateDraftTool(ctx context.Context, req *UpdateDraftToolRequest, draftTool *entity.ToolInfo) (err error) {
|
||||
if req.Method != nil && req.SubURL != nil {
|
||||
api := entity.UniqueToolAPI{
|
||||
SubURL: ptr.FromOrDefault(req.SubURL, ""),
|
||||
@ -633,9 +642,6 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
if req.Desc != nil {
|
||||
op.Summary = *req.Desc
|
||||
}
|
||||
if req.Parameters != nil {
|
||||
op.Parameters = req.Parameters
|
||||
}
|
||||
if req.APIExtend != nil {
|
||||
if op.Extensions == nil {
|
||||
op.Extensions = map[string]any{}
|
||||
@ -646,6 +652,12 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
}
|
||||
}
|
||||
|
||||
// update request parameters
|
||||
if req.Parameters != nil {
|
||||
op.Parameters = req.Parameters
|
||||
}
|
||||
|
||||
// update request body
|
||||
if req.RequestBody == nil {
|
||||
op.RequestBody = draftTool.Operation.RequestBody
|
||||
} else {
|
||||
@ -663,6 +675,7 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
op.RequestBody.Value.Content[model.MediaTypeJson] = mType
|
||||
}
|
||||
|
||||
// update responses
|
||||
if req.Responses == nil {
|
||||
op.Responses = draftTool.Operation.Responses
|
||||
} else {
|
||||
@ -706,11 +719,24 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
Operation: op,
|
||||
}
|
||||
|
||||
err = p.toolRepo.UpdateDraftTool(ctx, updatedTool)
|
||||
if err != nil {
|
||||
return errorx.Wrapf(err, "UpdateDraftTool failed, toolID=%d", req.ToolID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pluginServiceImpl) updateDraftToolDebugExample(ctx context.Context, draftPlugin *entity.PluginInfo,
|
||||
draftTool *entity.ToolInfo, save bool, example *common.DebugExample) (err error) {
|
||||
|
||||
components := draftPlugin.OpenapiDoc.Components
|
||||
if req.SaveExample != nil && !*req.SaveExample &&
|
||||
components != nil && components.Examples != nil {
|
||||
|
||||
if !save && components != nil && components.Examples != nil {
|
||||
delete(components.Examples, draftTool.Operation.OperationID)
|
||||
} else if req.DebugExample != nil {
|
||||
}
|
||||
|
||||
if save {
|
||||
if components == nil {
|
||||
components = &openapi3.Components{}
|
||||
}
|
||||
@ -721,14 +747,14 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
draftPlugin.OpenapiDoc.Components = components
|
||||
|
||||
reqExample, respExample := map[string]any{}, map[string]any{}
|
||||
if req.DebugExample.ReqExample != "" {
|
||||
err = sonic.UnmarshalString(req.DebugExample.ReqExample, &reqExample)
|
||||
if example.ReqExample != "" {
|
||||
err = sonic.UnmarshalString(example.ReqExample, &reqExample)
|
||||
if err != nil {
|
||||
return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid request example"))
|
||||
}
|
||||
}
|
||||
if req.DebugExample.RespExample != "" {
|
||||
err = sonic.UnmarshalString(req.DebugExample.RespExample, &respExample)
|
||||
if example.RespExample != "" {
|
||||
err = sonic.UnmarshalString(example.RespExample, &respExample)
|
||||
if err != nil {
|
||||
return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid response example"))
|
||||
}
|
||||
@ -744,9 +770,9 @@ func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateTool
|
||||
}
|
||||
}
|
||||
|
||||
err = p.toolRepo.UpdateDraftToolAndDebugExample(ctx, draftPlugin.ID, draftPlugin.OpenapiDoc, updatedTool)
|
||||
err = p.pluginRepo.UpdateDebugExample(ctx, draftPlugin.ID, draftPlugin.OpenapiDoc)
|
||||
if err != nil {
|
||||
return errorx.Wrapf(err, "UpdateDraftToolAndDebugExample failed, pluginID=%d, toolID=%d", draftPlugin.ID, req.ToolID)
|
||||
return errorx.Wrapf(err, "UpdateDebugExample failed, pluginID=%d", draftPlugin.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -194,7 +194,7 @@ func (p *pluginServiceImpl) getAccessTokenByAuthorizationCode(ctx context.Contex
|
||||
meta := ci.Meta
|
||||
info, exist, err := p.oauthRepo.GetAuthorizationCode(ctx, ci.Meta)
|
||||
if err != nil {
|
||||
return "", errorx.Wrapf(err, "GetAuthorizationCode failed, userID=%s, pluginID=%d, isDraft=%p",
|
||||
return "", errorx.Wrapf(err, "GetAuthorizationCode failed, userID=%s, pluginID=%d, isDraft=%t",
|
||||
meta.UserID, meta.PluginID, meta.IsDraft)
|
||||
}
|
||||
if !exist {
|
||||
|
||||
@ -57,7 +57,7 @@ type PluginService interface {
|
||||
|
||||
// Draft Tool
|
||||
MGetDraftTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error)
|
||||
UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error)
|
||||
UpdateDraftTool(ctx context.Context, req *UpdateDraftToolRequest) (err error)
|
||||
ConvertToOpenapi3Doc(ctx context.Context, req *ConvertToOpenapi3DocRequest) (resp *ConvertToOpenapi3DocResponse)
|
||||
CreateDraftToolsWithCode(ctx context.Context, req *CreateDraftToolsWithCodeRequest) (resp *CreateDraftToolsWithCodeResponse, err error)
|
||||
CheckPluginToolsDebugStatus(ctx context.Context, pluginID int64) (err error)
|
||||
@ -312,7 +312,7 @@ type PublishAPPPluginsResponse = model.PublishAPPPluginsResponse
|
||||
|
||||
type MGetPluginLatestVersionResponse = model.MGetPluginLatestVersionResponse
|
||||
|
||||
type UpdateToolDraftRequest struct {
|
||||
type UpdateDraftToolRequest struct {
|
||||
PluginID int64
|
||||
ToolID int64
|
||||
Name *string
|
||||
|
||||
@ -19,6 +19,7 @@ package workflow
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
@ -96,6 +97,8 @@ type Repository interface {
|
||||
|
||||
compose.CheckPointStore
|
||||
idgen.IDGenerator
|
||||
|
||||
GetKnowledgeRecallChatModel() model.BaseChatModel
|
||||
}
|
||||
|
||||
var repositorySingleton Repository
|
||||
|
||||
@ -102,7 +102,7 @@ func TestQuestionAnswer(t *testing.T) {
|
||||
mockTos := storageMock.NewMockStorage(ctrl)
|
||||
mockTos.EXPECT().GetObjectUrl(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
|
||||
repo := repo2.NewRepository(mockIDGen, db, redisClient, mockTos,
|
||||
checkpoint.NewRedisStore(redisClient))
|
||||
checkpoint.NewRedisStore(redisClient), nil)
|
||||
mockey.Mock(workflow.GetRepository).Return(repo).Build()
|
||||
|
||||
t.Run("answer directly, no structured output", func(t *testing.T) {
|
||||
|
||||
@ -223,9 +223,9 @@ func (s *NodeSchema) ToLLMConfig(ctx context.Context) (*llm.Config, error) {
|
||||
}
|
||||
|
||||
if fcParams.KnowledgeFCParam != nil && len(fcParams.KnowledgeFCParam.KnowledgeList) > 0 {
|
||||
kwChatModel, err := knowledgeRecallChatModel(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
kwChatModel := workflow2.GetRepository().GetKnowledgeRecallChatModel()
|
||||
if kwChatModel == nil {
|
||||
return nil, fmt.Errorf("workflow builtin chat model for knowledge recall not configured")
|
||||
}
|
||||
knowledgeOperator := crossknowledge.GetKnowledgeOperator()
|
||||
setting := fcParams.KnowledgeFCParam.GlobalSetting
|
||||
@ -650,15 +650,3 @@ func totRetrievalSearchType(s int64) (crossknowledge.SearchType, error) {
|
||||
return "", fmt.Errorf("invalid retrieval search type %v", s)
|
||||
}
|
||||
}
|
||||
|
||||
// knowledgeRecallChatModel the chat model used by the knowledge base recall in the LLM node, not the user-configured model
|
||||
func knowledgeRecallChatModel(ctx context.Context) (einomodel.BaseChatModel, error) {
|
||||
defaultChatModelParma := &model.LLMParams{
|
||||
ModelName: "豆包·1.5·Pro·32k",
|
||||
ModelType: 1,
|
||||
Temperature: ptr.Of(0.5),
|
||||
MaxTokens: 4096,
|
||||
}
|
||||
m, _, err := model.GetManager().GetModel(ctx, defaultChatModelParma)
|
||||
return m, err
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/execute"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/model"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo/dal/query"
|
||||
cm "github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
@ -66,10 +67,11 @@ type RepositoryImpl struct {
|
||||
workflow.InterruptEventStore
|
||||
workflow.CancelSignalStore
|
||||
workflow.ExecuteHistoryStore
|
||||
builtinModel cm.BaseChatModel
|
||||
}
|
||||
|
||||
func NewRepository(idgen idgen.IDGenerator, db *gorm.DB, redis *redis.Client, tos storage.Storage,
|
||||
cpStore einoCompose.CheckPointStore) workflow.Repository {
|
||||
cpStore einoCompose.CheckPointStore, chatModel cm.BaseChatModel) workflow.Repository {
|
||||
return &RepositoryImpl{
|
||||
IDGenerator: idgen,
|
||||
query: query.Use(db),
|
||||
@ -86,6 +88,7 @@ func NewRepository(idgen idgen.IDGenerator, db *gorm.DB, redis *redis.Client, to
|
||||
query: query.Use(db),
|
||||
redis: redis,
|
||||
},
|
||||
builtinModel: chatModel,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1583,6 +1586,10 @@ func (r *RepositoryImpl) BatchCreateConnectorWorkflowVersion(ctx context.Context
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RepositoryImpl) GetKnowledgeRecallChatModel() cm.BaseChatModel {
|
||||
return r.builtinModel
|
||||
}
|
||||
|
||||
func filterDisabledAPIParameters(parametersCfg []*workflow3.APIParameter, m map[string]any) map[string]any {
|
||||
result := make(map[string]any, len(m))
|
||||
responseParameterMap := slices.ToMap(parametersCfg, func(p *workflow3.APIParameter) (string, *workflow3.APIParameter) {
|
||||
|
||||
@ -39,6 +39,7 @@ import (
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/adaptor"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/compose"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/repo"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/chatmodel"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
||||
@ -67,8 +68,8 @@ func NewWorkflowService(repo workflow.Repository) workflow.Service {
|
||||
}
|
||||
|
||||
func NewWorkflowRepository(idgen idgen.IDGenerator, db *gorm.DB, redis *redis.Client, tos storage.Storage,
|
||||
cpStore einoCompose.CheckPointStore) workflow.Repository {
|
||||
return repo.NewRepository(idgen, db, redis, tos, cpStore)
|
||||
cpStore einoCompose.CheckPointStore, chatModel chatmodel.BaseChatModel) workflow.Repository {
|
||||
return repo.NewRepository(idgen, db, redis, tos, cpStore, chatModel)
|
||||
}
|
||||
|
||||
func (i *impl) ListNodeMeta(ctx context.Context, nodeTypes map[entity.NodeType]bool) (map[string][]*entity.NodeTypeMeta, []entity.Category, error) {
|
||||
|
||||
@ -54,11 +54,12 @@ require github.com/alicebob/miniredis/v2 v2.34.0
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1
|
||||
github.com/cloudwego/eino-ext/components/embedding/ark v0.0.0-20250522060253-ddb617598b09
|
||||
github.com/cloudwego/eino-ext/components/embedding/ollama v0.0.0-20250728060543-79ec300857b8
|
||||
github.com/cloudwego/eino-ext/components/embedding/openai v0.0.0-20250522060253-ddb617598b09
|
||||
github.com/cloudwego/eino-ext/components/model/gemini v0.1.2
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.0.0-20250610035057-2c4e7c8488a5
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.0
|
||||
github.com/cloudwego/eino-ext/components/model/qwen v0.0.0-20250612061754-5a3deb091dc5
|
||||
github.com/dimchansky/utfbom v1.1.1
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.10
|
||||
@ -84,7 +85,6 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1 // indirect
|
||||
github.com/cloudwego/gopkg v0.1.4 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7 // indirect
|
||||
@ -111,10 +111,10 @@ require (
|
||||
require (
|
||||
github.com/anthropics/anthropic-sdk-go v1.4.0 // indirect
|
||||
github.com/avast/retry-go v3.0.0+incompatible // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.6
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.54 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.1
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.54
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 // indirect
|
||||
@ -241,7 +241,7 @@ require (
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
|
||||
@ -822,12 +822,8 @@ github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHS
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.33.0 h1:Evgm4DI9imD81V0WwD+TN4DCwjUMdc94TrduMLbgZJs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.33.0/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.6 h1:zJqGjVbRdTPojeCGWn5IR5pbJwSQSBh5RWFTQcEQGdU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.6/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.1 h1:JZhGawAyZ/EuJeBtbQYnaoftczcb2drR2Iq36Wgz4sQ=
|
||||
@ -836,12 +832,8 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.54 h1:4UmqeOqJPvdvASZWrKlhzpRahAu
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.54/go.mod h1:RTdfo0P0hbbTxIhmQrOsC/PquBZGabEPnCaxxKRPSnI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24 h1:5grmdTdMsovn9kPZPI23Hhvp0ZyNm5cRO+IZFIYiAfw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24/go.mod h1:zqi7TVKTswH3Ozq28PkmBmgzG1tona7mo9G2IJg4Cis=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 h1:igORFSiH3bfq4lxKFkTSYDhJEUCYo6C8VKiWJjYwQuQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28/go.mod h1:3So8EA/aAYm36L7XIvCVwLa0s5N0P7o2b1oqnx/2R4g=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 h1:osMWfm/sC/L4tvEdQ65Gri5ZZDCUpuYJZbTTDrsn4I0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37/go.mod h1:ZV2/1fbjOPr4G4v38G3Ww5TBT4+hmsK45s/rxu1fGy0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 h1:1mOW9zAUMhTSrMDssEHS/ajx8JcAj/IcftzcmNlmVLI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28/go.mod h1:kGlXVIWDfvt2Ox5zEaNglmq0hXPHgQFNMix33Tw22jA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 h1:v+X21AvTb2wZ+ycg1gx+orkB/9U6L7AOp93R7qYxsxM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37/go.mod h1:G0uM1kyssELxmJ2VZEfG0q2npObR3BAkF3c1VsfVnfs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
@ -849,14 +841,10 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJN
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 h1:XTZZ0I3SZUHAtBLBU6395ad+VOblE0DwQP6MuaNeics=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37/go.mod h1:Pi6ksbniAWVwu2S8pEzcYPyhUkAcLaufxN7PfAUQjBk=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 h1:M5/B8JUaCI8+9QD+u3S/f4YHpvqE9RpSkV3rf0Iks2w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5/go.mod h1:Bktzci1bwdbpuLiu3AOksiNPMl/LLKmX1TWmqp2xbvs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 h1:TQmKDyETFGiXVhZfQ/I0cCFziqqX58pi4tKJGYGFSz0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9/go.mod h1:HVLPK2iHQBUx7HfZeOQSEu3v2ubZaAY2YPbAm5/WUyY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 h1:vvbXsA2TVO80/KT7ZqCbx934dt6PY+vQ8hZpUZ/cpYg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18/go.mod h1:m2JJHledjBGNMsLOF1g9gbAxprzq3KjC8e4lxtn+eWg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 h1:OS2e0SKqsU2LiJPqL8u9x41tKc6MMEHrWjLVLn3oysg=
|
||||
@ -870,8 +858,6 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.10/go.mod h1:Fzsj6lZEb8AkTE5S
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9 h1:BRVDbewN6VZcwr+FBOszDKvYeXY1kJ+GGMCcpghlw0U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.9/go.mod h1:f6vjfZER1M17Fokn0IzssOTMT2N8ZSq+7jnNF0tArvw=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
|
||||
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
@ -954,8 +940,8 @@ github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250715055739-0d
|
||||
github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250715055739-0d0e28441a2f/go.mod h1:3XV+kHvG6IrVj4WXlquihx8i7a8fUKa09PzuS7IvF2k=
|
||||
github.com/cloudwego/eino-ext/components/model/gemini v0.1.2 h1:bt9xftOQhP0Nuh1Po6ZNljSzBvv11Aw6hFLR7V1sLd8=
|
||||
github.com/cloudwego/eino-ext/components/model/gemini v0.1.2/go.mod h1:1tv89uZ9hR/4AyQ+9yxFWLn52GaJDKtPXdEY7WZdyZc=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.0.0-20250610035057-2c4e7c8488a5 h1:GkAAQHQkb1cOTwm6uRokj4lM//wrt/3AkMwTxyFJUg4=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.0.0-20250610035057-2c4e7c8488a5/go.mod h1:giNUFqA+V7xrm/EDvH7JFnDqoWI+e2m1SVAnReU+Fd8=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.0 h1:FW067iMfg3EZbUaZIo8v3i2ILBAZDzY23/9pbprvE0M=
|
||||
github.com/cloudwego/eino-ext/components/model/ollama v0.1.0/go.mod h1:+qA5kkUCM0mIrXGSNzxLcjxh6K1AghPNigtEyyMdkOc=
|
||||
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250715055739-0d0e28441a2f h1:ovS39vuN2JW+C/O9jtEmOUuLEY4fw0yYh8//yhMfJNM=
|
||||
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250715055739-0d0e28441a2f/go.mod h1:2mFQQnlhJrNgbW6YX1MOUUfXkGSbTz9Ylx37fbR0xBo=
|
||||
github.com/cloudwego/eino-ext/components/model/qwen v0.0.0-20250612061754-5a3deb091dc5 h1:4zAZiNo/PkeVc0Gw8YLpzpbR8zDzccL7H5PLqTuGhv4=
|
||||
|
||||
@ -123,7 +123,6 @@ func (p *Parameter) GetString(tp DefaultType) (string, error) {
|
||||
}
|
||||
|
||||
type ModelMeta struct {
|
||||
Name string `yaml:"name"`
|
||||
Protocol chatmodel.Protocol `yaml:"protocol"` // 模型通信协议
|
||||
Capability *Capability `yaml:"capability"` // 模型能力
|
||||
ConnConfig *chatmodel.Config `yaml:"conn_config"` // 模型连接配置
|
||||
|
||||
6
backend/infra/impl/cache/redis/redis.go
vendored
6
backend/infra/impl/cache/redis/redis.go
vendored
@ -27,9 +27,11 @@ type Client = redis.Client
|
||||
|
||||
func New() *redis.Client {
|
||||
addr := os.Getenv("REDIS_ADDR")
|
||||
password := os.Getenv("REDIS_PASSWORD")
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: addr, // Redis地址
|
||||
DB: 0, // 默认数据库
|
||||
Addr: addr, // Redis地址
|
||||
DB: 0, // 默认数据库
|
||||
Password: password,
|
||||
// 连接池配置
|
||||
PoolSize: 100, // 最大连接数(建议设置为CPU核心数*10)
|
||||
MinIdleConns: 10, // 最小空闲连接
|
||||
|
||||
@ -24,12 +24,12 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
"github.com/volcengine/volc-sdk-golang/service/visual"
|
||||
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/document/ocr"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
||||
@ -249,6 +249,11 @@ func formatTablesInDocument(input []*schema.Document) (output []*schema.Document
|
||||
values = append(values, col.Name)
|
||||
}
|
||||
write(values)
|
||||
if colOnly, err := document.GetDocumentColumnsOnly(doc); err != nil {
|
||||
return nil, err
|
||||
} else if colOnly {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
data, err := document.GetDocumentColumnData(doc)
|
||||
|
||||
@ -179,7 +179,7 @@ func TestBuiltinEmbeddingIntegration(t *testing.T) {
|
||||
Model: os.Getenv("OPENAI_EMBEDDING_MODEL"),
|
||||
Dimensions: ptr.Of(1024),
|
||||
}
|
||||
emb, err := wrap.NewOpenAIEmbedder(ctx, embConfig, 1024)
|
||||
emb, err := wrap.NewOpenAIEmbedder(ctx, embConfig, 1024, 100)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg := &ManagerConfig{
|
||||
|
||||
@ -25,31 +25,32 @@ import (
|
||||
|
||||
"github.com/cloudwego/eino-ext/components/embedding/ark"
|
||||
"github.com/cloudwego/eino/components/embedding"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
||||
|
||||
contract "github.com/coze-dev/coze-studio/backend/infra/contract/embedding"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
"github.com/coze-dev/coze-studio/backend/types/errno"
|
||||
)
|
||||
|
||||
func NewArkEmbedder(ctx context.Context, config *ark.EmbeddingConfig, dimensions int64) (contract.Embedder, error) {
|
||||
func NewArkEmbedder(ctx context.Context, config *ark.EmbeddingConfig, dimensions int64, batchSize int) (contract.Embedder, error) {
|
||||
emb, err := ark.NewEmbedder(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &embWrap{dims: dimensions, Embedder: emb}, nil
|
||||
return &embWrap{dims: dimensions, batchSize: batchSize, Embedder: emb}, nil
|
||||
}
|
||||
|
||||
type embWrap struct {
|
||||
dims int64
|
||||
dims int64
|
||||
batchSize int
|
||||
embedding.Embedder
|
||||
}
|
||||
|
||||
func (d embWrap) EmbedStrings(ctx context.Context, texts []string, opts ...embedding.Option) ([][]float64, error) {
|
||||
resp := make([][]float64, 0, len(texts))
|
||||
for _, part := range slices.Chunks(texts, 100) {
|
||||
for _, part := range slices.Chunks(texts, d.batchSize) {
|
||||
partResult, err := d.Embedder.EmbedStrings(ctx, part, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -22,18 +22,16 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
opt "github.com/cloudwego/eino/components/embedding"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/embedding"
|
||||
)
|
||||
|
||||
const (
|
||||
pathDim = "/dimension"
|
||||
pathEmbed = "/embedding"
|
||||
)
|
||||
const pathEmbed = "/embedding"
|
||||
|
||||
type embedReq struct {
|
||||
Texts []string `json:"texts"`
|
||||
@ -45,108 +43,90 @@ type embedResp struct {
|
||||
Sparse []map[int]float64 `json:"sparse"`
|
||||
}
|
||||
|
||||
func NewEmbedding(addr string) (embedding.Embedder, error) {
|
||||
func NewEmbedding(addr string, dims int64, batchSize int) (embedding.Embedder, error) {
|
||||
cli := &http.Client{Timeout: time.Second * 30}
|
||||
req, err := http.NewRequest(http.MethodGet, addr+pathDim, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dim, err := strconv.ParseInt(string(b), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &embedder{
|
||||
cli: cli,
|
||||
addr: addr,
|
||||
dim: dim,
|
||||
cli: cli,
|
||||
addr: addr,
|
||||
dim: dims,
|
||||
batchSize: batchSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type embedder struct {
|
||||
cli *http.Client
|
||||
addr string
|
||||
dim int64
|
||||
cli *http.Client
|
||||
addr string
|
||||
dim int64
|
||||
batchSize int
|
||||
}
|
||||
|
||||
func (e *embedder) EmbedStrings(ctx context.Context, texts []string, opts ...opt.Option) ([][]float64, error) {
|
||||
rb, err := json.Marshal(&embedReq{
|
||||
Texts: texts,
|
||||
NeedSparse: false,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
dense := make([][]float64, 0, len(texts))
|
||||
for _, part := range slices.Chunks(texts, e.batchSize) {
|
||||
rb, err := json.Marshal(&embedReq{
|
||||
Texts: part,
|
||||
NeedSparse: false,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.addr+pathEmbed, bytes.NewReader(rb))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
resp, err := e.do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dense = append(dense, resp.Dense...)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.addr+pathEmbed, bytes.NewReader(rb))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
resp, err := e.cli.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &embedResp{}
|
||||
if err = json.Unmarshal(b, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Dense, nil
|
||||
return dense, nil
|
||||
}
|
||||
|
||||
func (e *embedder) EmbedStringsHybrid(ctx context.Context, texts []string, opts ...opt.Option) ([][]float64, []map[int]float64, error) {
|
||||
rb, err := json.Marshal(&embedReq{
|
||||
Texts: texts,
|
||||
NeedSparse: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
dense := make([][]float64, 0, len(texts))
|
||||
sparse := make([]map[int]float64, 0, len(texts))
|
||||
for _, part := range slices.Chunks(texts, e.batchSize) {
|
||||
rb, err := json.Marshal(&embedReq{
|
||||
Texts: part,
|
||||
NeedSparse: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.addr+pathEmbed, bytes.NewReader(rb))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
resp, err := e.do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dense = append(dense, resp.Dense...)
|
||||
sparse = append(sparse, resp.Sparse...)
|
||||
}
|
||||
return dense, sparse, nil
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.addr+pathEmbed, bytes.NewReader(rb))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
func (e *embedder) do(req *http.Request) (*embedResp, error) {
|
||||
resp, err := e.cli.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &embedResp{}
|
||||
if err = json.Unmarshal(b, r); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Dense, r.Sparse, nil
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (e *embedder) Dimensions() int64 {
|
||||
|
||||
@ -31,7 +31,7 @@ func TestHTTPEmbedding(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
emb, err := NewEmbedding("http://127.0.0.1:6543")
|
||||
emb, err := NewEmbedding("http://127.0.0.1:6543", 1024, 10)
|
||||
assert.NoError(t, err)
|
||||
texts := []string{
|
||||
"hello",
|
||||
|
||||
@ -27,13 +27,14 @@ import (
|
||||
)
|
||||
|
||||
type denseOnlyWrap struct {
|
||||
dims int64
|
||||
dims int64
|
||||
batchSize int
|
||||
embedding.Embedder
|
||||
}
|
||||
|
||||
func (d denseOnlyWrap) EmbedStrings(ctx context.Context, texts []string, opts ...embedding.Option) ([][]float64, error) {
|
||||
resp := make([][]float64, 0, len(texts))
|
||||
for _, part := range slices.Chunks(texts, 100) {
|
||||
for _, part := range slices.Chunks(texts, d.batchSize) {
|
||||
partResult, err := d.Embedder.EmbedStrings(ctx, part, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -20,13 +20,14 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino-ext/components/embedding/ollama"
|
||||
|
||||
contract "github.com/coze-dev/coze-studio/backend/infra/contract/embedding"
|
||||
)
|
||||
|
||||
func NewOllamaEmbedder(ctx context.Context, config *ollama.EmbeddingConfig, dimensions int64) (contract.Embedder, error) {
|
||||
func NewOllamaEmbedder(ctx context.Context, config *ollama.EmbeddingConfig, dimensions int64, batchSize int) (contract.Embedder, error) {
|
||||
emb, err := ollama.NewEmbedder(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &denseOnlyWrap{dims: dimensions, Embedder: emb}, nil
|
||||
return &denseOnlyWrap{dims: dimensions, batchSize: batchSize, Embedder: emb}, nil
|
||||
}
|
||||
|
||||
@ -24,10 +24,10 @@ import (
|
||||
contract "github.com/coze-dev/coze-studio/backend/infra/contract/embedding"
|
||||
)
|
||||
|
||||
func NewOpenAIEmbedder(ctx context.Context, config *openai.EmbeddingConfig, dimensions int64) (contract.Embedder, error) {
|
||||
func NewOpenAIEmbedder(ctx context.Context, config *openai.EmbeddingConfig, dimensions int64, batchSize int) (contract.Embedder, error) {
|
||||
emb, err := openai.NewEmbedder(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &denseOnlyWrap{dims: dimensions, Embedder: emb}, nil
|
||||
return &denseOnlyWrap{dims: dimensions, batchSize: batchSize, Embedder: emb}, nil
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
@ -25,5 +26,10 @@ import (
|
||||
|
||||
func New() (*gorm.DB, error) {
|
||||
dsn := os.Getenv("MYSQL_DSN")
|
||||
return gorm.Open(mysql.Open(dsn))
|
||||
db, err := gorm.Open(mysql.Open(dsn))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mysql open, dsn: %s, err: %w", dsn, err)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@ -23,9 +23,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
@ -33,6 +31,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/imagex"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/storage/proxy"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
@ -211,27 +210,9 @@ func (m *minioClient) GetObjectUrl(ctx context.Context, objectKey string, opts .
|
||||
}
|
||||
|
||||
// logs.CtxDebugf(ctx, "[GetObjectUrl] origin presignedURL.String = %s", presignedURL.String())
|
||||
|
||||
proxyPort := os.Getenv(consts.MinIOProxyEndpoint) // :8889
|
||||
if len(proxyPort) > 0 {
|
||||
currentHost, ok := ctxcache.Get[string](ctx, consts.HostKeyInCtx)
|
||||
if !ok {
|
||||
return presignedURL.String(), nil
|
||||
}
|
||||
|
||||
currentScheme, ok := ctxcache.Get[string](ctx, consts.RequestSchemeKeyInCtx)
|
||||
if !ok {
|
||||
return presignedURL.String(), nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(currentHost)
|
||||
if err != nil {
|
||||
host = currentHost
|
||||
}
|
||||
minioProxyHost := host + proxyPort
|
||||
presignedURL.Host = minioProxyHost
|
||||
presignedURL.Scheme = currentScheme
|
||||
// logs.CtxDebugf(ctx, "[GetObjectUrl] reset presignedURL.String = %s", presignedURL.String())
|
||||
ok, proxyURL := proxy.CheckIfNeedReplaceHost(ctx, presignedURL.String())
|
||||
if ok {
|
||||
return proxyURL, nil
|
||||
}
|
||||
|
||||
return presignedURL.String(), nil
|
||||
@ -265,7 +246,6 @@ func (m *minioClient) GetUploadAuth(ctx context.Context, opt ...imagex.UploadAut
|
||||
}
|
||||
|
||||
func (m *minioClient) GetResourceURL(ctx context.Context, uri string, opts ...imagex.GetResourceOpt) (*imagex.ResourceURL, error) {
|
||||
|
||||
url, err := m.GetObjectUrl(ctx, uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -273,11 +253,12 @@ func (m *minioClient) GetResourceURL(ctx context.Context, uri string, opts ...im
|
||||
return &imagex.ResourceURL{
|
||||
URL: url,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (m *minioClient) Upload(ctx context.Context, data []byte, opts ...imagex.UploadAuthOpt) (*imagex.UploadResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *minioClient) GetUploadAuthWithExpire(ctx context.Context, expire time.Duration, opt ...imagex.UploadAuthOpt) (*imagex.SecurityToken, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
63
backend/infra/impl/storage/proxy/proxy.go
Normal file
63
backend/infra/impl/storage/proxy/proxy.go
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
"github.com/coze-dev/coze-studio/backend/types/consts"
|
||||
)
|
||||
|
||||
func CheckIfNeedReplaceHost(ctx context.Context, originURLStr string) (ok bool, proxyURL string) {
|
||||
// url parse
|
||||
originURL, err := url.Parse(originURLStr)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "[CheckIfNeedReplaceHost] url parse failed, err: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
proxyPort := os.Getenv(consts.MinIOProxyEndpoint) // :8889
|
||||
if proxyPort == "" {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
currentHost, ok := ctxcache.Get[string](ctx, consts.HostKeyInCtx)
|
||||
if !ok {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
currentScheme, ok := ctxcache.Get[string](ctx, consts.RequestSchemeKeyInCtx)
|
||||
if !ok {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(currentHost)
|
||||
if err != nil {
|
||||
host = currentHost
|
||||
}
|
||||
|
||||
minioProxyHost := host + proxyPort
|
||||
originURL.Host = minioProxyHost
|
||||
originURL.Scheme = currentScheme
|
||||
logs.CtxDebugf(ctx, "[CheckIfNeedReplaceHost] reset originURL.String = %s", originURL.String())
|
||||
return true, originURL.String()
|
||||
}
|
||||
@ -21,9 +21,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
@ -33,6 +30,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/imagex"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/storage/proxy"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
||||
@ -219,34 +217,9 @@ func (t *s3Client) GetObjectUrl(ctx context.Context, objectKey string, opts ...s
|
||||
return "", fmt.Errorf("get object presigned url failed: %v", err)
|
||||
}
|
||||
|
||||
// url parse
|
||||
url, err := url.Parse(req.URL)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "[GetObjectUrl] url parse failed, err: %v", err)
|
||||
return req.URL, nil
|
||||
}
|
||||
|
||||
proxyPort := os.Getenv(consts.MinIOProxyEndpoint) // :8889
|
||||
if len(proxyPort) > 0 {
|
||||
currentHost, ok := ctxcache.Get[string](ctx, consts.HostKeyInCtx)
|
||||
if !ok {
|
||||
return req.URL, nil
|
||||
}
|
||||
|
||||
currentScheme, ok := ctxcache.Get[string](ctx, consts.RequestSchemeKeyInCtx)
|
||||
if !ok {
|
||||
return req.URL, nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(currentHost)
|
||||
if err != nil {
|
||||
host = currentHost
|
||||
}
|
||||
minioProxyHost := host + proxyPort
|
||||
url.Host = minioProxyHost
|
||||
url.Scheme = currentScheme
|
||||
logs.CtxInfof(ctx, "[GetObjectUrl] reset ORG.URL = %s TOS.URL = %s", req.URL, url.String())
|
||||
return url.String(), nil
|
||||
ok, proxyURL := proxy.CheckIfNeedReplaceHost(ctx, req.URL)
|
||||
if ok {
|
||||
return proxyURL, nil
|
||||
}
|
||||
|
||||
return req.URL, nil
|
||||
@ -258,7 +231,6 @@ func (i *s3Client) GetUploadHost(ctx context.Context) string {
|
||||
return ""
|
||||
}
|
||||
return currentHost + consts.ApplyUploadActionURI
|
||||
|
||||
}
|
||||
|
||||
func (t *s3Client) GetServerID() string {
|
||||
|
||||
@ -21,10 +21,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"
|
||||
@ -32,6 +29,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/imagex"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
|
||||
"github.com/coze-dev/coze-studio/backend/infra/impl/storage/proxy"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
|
||||
@ -213,34 +211,9 @@ func (t *tosClient) GetObjectUrl(ctx context.Context, objectKey string, opts ...
|
||||
return "", err
|
||||
}
|
||||
|
||||
// url parse
|
||||
url, err := url.Parse(output.SignedUrl)
|
||||
if err != nil {
|
||||
logs.CtxWarnf(ctx, "[GetObjectUrl] url parse failed, err: %v", err)
|
||||
return output.SignedUrl, nil
|
||||
}
|
||||
|
||||
proxyPort := os.Getenv(consts.MinIOProxyEndpoint) // :8889
|
||||
if len(proxyPort) > 0 {
|
||||
currentHost, ok := ctxcache.Get[string](ctx, consts.HostKeyInCtx)
|
||||
if !ok {
|
||||
return output.SignedUrl, nil
|
||||
}
|
||||
|
||||
currentScheme, ok := ctxcache.Get[string](ctx, consts.RequestSchemeKeyInCtx)
|
||||
if !ok {
|
||||
return output.SignedUrl, nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(currentHost)
|
||||
if err != nil {
|
||||
host = currentHost
|
||||
}
|
||||
minioProxyHost := host + proxyPort
|
||||
url.Host = minioProxyHost
|
||||
url.Scheme = currentScheme
|
||||
// logs.CtxDebugf(ctx, "[GetObjectUrl] reset \n ORG.URL = %s \n TOS.URL = %s", output.SignedUrl, url.String())
|
||||
return url.String(), nil
|
||||
ok, proxyURL := proxy.CheckIfNeedReplaceHost(ctx, output.SignedUrl)
|
||||
if ok {
|
||||
return proxyURL, nil
|
||||
}
|
||||
|
||||
return output.SignedUrl, nil
|
||||
|
||||
@ -651,7 +651,7 @@ func (mr *MockPluginServiceMockRecorder) UpdateDraftPluginWithCode(ctx, req any)
|
||||
}
|
||||
|
||||
// UpdateDraftTool mocks base method.
|
||||
func (m *MockPluginService) UpdateDraftTool(ctx context.Context, req *service.UpdateToolDraftRequest) error {
|
||||
func (m *MockPluginService) UpdateDraftTool(ctx context.Context, req *service.UpdateDraftToolRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateDraftTool", ctx, req)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
model "github.com/cloudwego/eino/components/model"
|
||||
compose "github.com/cloudwego/eino/compose"
|
||||
schema "github.com/cloudwego/eino/schema"
|
||||
workflow "github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/workflow"
|
||||
@ -26,7 +27,6 @@ import (
|
||||
type MockService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockServiceMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockServiceMockRecorder is the mock recorder for MockService.
|
||||
@ -364,17 +364,17 @@ func (mr *MockServiceMockRecorder) ReleaseApplicationWorkflows(ctx, appID, confi
|
||||
}
|
||||
|
||||
// Save mocks base method.
|
||||
func (m *MockService) Save(ctx context.Context, id int64, arg2 string) error {
|
||||
func (m *MockService) Save(ctx context.Context, id int64, schema string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Save", ctx, id, arg2)
|
||||
ret := m.ctrl.Call(m, "Save", ctx, id, schema)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Save indicates an expected call of Save.
|
||||
func (mr *MockServiceMockRecorder) Save(ctx, id, arg2 any) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) Save(ctx, id, schema any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockService)(nil).Save), ctx, id, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockService)(nil).Save), ctx, id, schema)
|
||||
}
|
||||
|
||||
// StreamExecute mocks base method.
|
||||
@ -528,7 +528,6 @@ func (mr *MockServiceMockRecorder) WorkflowAsModelTool(ctx, policies any) *gomoc
|
||||
type MockRepository struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRepositoryMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockRepositoryMockRecorder is the mock recorder for MockRepository.
|
||||
@ -548,6 +547,20 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BatchCreateConnectorWorkflowVersion mocks base method.
|
||||
func (m *MockRepository) BatchCreateConnectorWorkflowVersion(ctx context.Context, appID, connectorID int64, workflowIDs []int64, version string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BatchCreateConnectorWorkflowVersion", ctx, appID, connectorID, workflowIDs, version)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BatchCreateConnectorWorkflowVersion indicates an expected call of BatchCreateConnectorWorkflowVersion.
|
||||
func (mr *MockRepositoryMockRecorder) BatchCreateConnectorWorkflowVersion(ctx, appID, connectorID, workflowIDs, version any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCreateConnectorWorkflowVersion", reflect.TypeOf((*MockRepository)(nil).BatchCreateConnectorWorkflowVersion), ctx, appID, connectorID, workflowIDs, version)
|
||||
}
|
||||
|
||||
// CancelAllRunningNodes mocks base method.
|
||||
func (m *MockRepository) CancelAllRunningNodes(ctx context.Context, wfExeID int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
@ -784,6 +797,20 @@ func (mr *MockRepositoryMockRecorder) GetFirstInterruptEvent(ctx, wfExeID any) *
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFirstInterruptEvent", reflect.TypeOf((*MockRepository)(nil).GetFirstInterruptEvent), ctx, wfExeID)
|
||||
}
|
||||
|
||||
// GetKnowledgeRecallChatModel mocks base method.
|
||||
func (m *MockRepository) GetKnowledgeRecallChatModel() model.BaseChatModel {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetKnowledgeRecallChatModel")
|
||||
ret0, _ := ret[0].(model.BaseChatModel)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetKnowledgeRecallChatModel indicates an expected call of GetKnowledgeRecallChatModel.
|
||||
func (mr *MockRepositoryMockRecorder) GetKnowledgeRecallChatModel() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKnowledgeRecallChatModel", reflect.TypeOf((*MockRepository)(nil).GetKnowledgeRecallChatModel))
|
||||
}
|
||||
|
||||
// GetLatestVersion mocks base method.
|
||||
func (m *MockRepository) GetLatestVersion(ctx context.Context, id int64) (*vo.VersionInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -936,6 +963,21 @@ func (mr *MockRepositoryMockRecorder) GetWorkflowExecution(ctx, id any) *gomock.
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkflowExecution", reflect.TypeOf((*MockRepository)(nil).GetWorkflowExecution), ctx, id)
|
||||
}
|
||||
|
||||
// IsApplicationConnectorWorkflowVersion mocks base method.
|
||||
func (m *MockRepository) IsApplicationConnectorWorkflowVersion(ctx context.Context, connectorID, workflowID int64, version string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsApplicationConnectorWorkflowVersion", ctx, connectorID, workflowID, version)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IsApplicationConnectorWorkflowVersion indicates an expected call of IsApplicationConnectorWorkflowVersion.
|
||||
func (mr *MockRepositoryMockRecorder) IsApplicationConnectorWorkflowVersion(ctx, connectorID, workflowID, version any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApplicationConnectorWorkflowVersion", reflect.TypeOf((*MockRepository)(nil).IsApplicationConnectorWorkflowVersion), ctx, connectorID, workflowID, version)
|
||||
}
|
||||
|
||||
// ListInterruptEvents mocks base method.
|
||||
func (m *MockRepository) ListInterruptEvents(ctx context.Context, wfExeID int64) ([]*entity.InterruptEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -1172,6 +1214,20 @@ func (mr *MockRepositoryMockRecorder) UpdateNodeExecution(ctx, execution any) *g
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodeExecution", reflect.TypeOf((*MockRepository)(nil).UpdateNodeExecution), ctx, execution)
|
||||
}
|
||||
|
||||
// UpdateNodeExecutionStreaming mocks base method.
|
||||
func (m *MockRepository) UpdateNodeExecutionStreaming(ctx context.Context, execution *entity.NodeExecution) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateNodeExecutionStreaming", ctx, execution)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateNodeExecutionStreaming indicates an expected call of UpdateNodeExecutionStreaming.
|
||||
func (mr *MockRepositoryMockRecorder) UpdateNodeExecutionStreaming(ctx, execution any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodeExecutionStreaming", reflect.TypeOf((*MockRepository)(nil).UpdateNodeExecutionStreaming), ctx, execution)
|
||||
}
|
||||
|
||||
// UpdateWorkflowDraftTestRunSuccess mocks base method.
|
||||
func (m *MockRepository) UpdateWorkflowDraftTestRunSuccess(ctx context.Context, id int64) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@ -74,9 +74,10 @@ func startHttpServer() {
|
||||
server.WithMaxRequestBodySize(int(maxSize)),
|
||||
}
|
||||
|
||||
useSSL := getEnv("USE_SSL", "0")
|
||||
useSSL := getEnv(consts.UseSSL, "0")
|
||||
if useSSL == "1" {
|
||||
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
|
||||
cert, err := tls.LoadX509KeyPair(getEnv(consts.SSLCertFile, ""),
|
||||
getEnv(consts.SSLKeyFile, ""))
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
@ -193,10 +194,12 @@ func asyncStartMinioProxyServer(ctx context.Context) {
|
||||
originDirector(req)
|
||||
req.Host = req.URL.Host
|
||||
}
|
||||
useSSL := getEnv("USE_SSL", "0")
|
||||
useSSL := getEnv(consts.UseSSL, "0")
|
||||
if useSSL == "1" {
|
||||
logs.Infof("Minio proxy server is listening on %s with SSL", minioProxyEndpoint)
|
||||
err := http.ListenAndServeTLS(minioProxyEndpoint, "cert.pem", "key.pem", proxy)
|
||||
err := http.ListenAndServeTLS(minioProxyEndpoint,
|
||||
getEnv(consts.SSLCertFile, ""),
|
||||
getEnv(consts.SSLKeyFile, ""), proxy)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Bootstrapping Coze Studio... 07-30"
|
||||
|
||||
# Set up Elasticsearch
|
||||
echo "Setting up Elasticsearch..."
|
||||
/app/setup_es.sh --index-dir /app/es_index_schemas
|
||||
|
||||
# Start the proxy application in the background
|
||||
echo "Starting proxy application..."
|
||||
/app/proxy >/tmp/proxy.log 2>&1 &
|
||||
echo "Proxy application started in background."
|
||||
|
||||
# Start the main application in the foreground
|
||||
echo "Starting main application..."
|
||||
/app/opencoze
|
||||
|
||||
@ -81,6 +81,10 @@ const (
|
||||
CodeRunnerNodeModulesDir = "CODE_RUNNER_NODE_MODULES_DIR"
|
||||
CodeRunnerTimeoutSeconds = "CODE_RUNNER_TIMEOUT_SECONDS"
|
||||
CodeRunnerMemoryLimitMB = "CODE_RUNNER_MEMORY_LIMIT_MB"
|
||||
|
||||
UseSSL = "USE_SSL"
|
||||
SSLCertFile = "SSL_CERT_FILE"
|
||||
SSLKeyFile = "SSL_KEY_FILE"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import type {
|
||||
IPlugin,
|
||||
IHooks,
|
||||
@ -33,7 +33,7 @@ export default class SelectTeamPlugin implements IPlugin {
|
||||
apply(hooks: IHooks): void {
|
||||
hooks.prompts.tap("SelectTeamPlugin", (prompts: IPromptsHookParams) => {
|
||||
|
||||
// 只留下以team-为前缀的
|
||||
// Leave only the prefix team-
|
||||
const teamNamePrefix = /^team-/;
|
||||
const choices = rushJson.allowedProjectTags.filter(
|
||||
teamName => teamNamePrefix.test(teamName)
|
||||
@ -41,22 +41,22 @@ export default class SelectTeamPlugin implements IPlugin {
|
||||
teamName => teamName.replace(teamNamePrefix, '')
|
||||
);
|
||||
|
||||
// unshift一个问题,使得用户选择完模版后展示该问题。
|
||||
// Unshift an issue, causing the user to display the issue after selecting a template.
|
||||
prompts.promptQueue.unshift({
|
||||
type: "list",
|
||||
name: "team",
|
||||
message: "Select your team",
|
||||
choices,
|
||||
default: 0, // 默认选择choices[0]
|
||||
default: 0, // Default choices [0]
|
||||
});
|
||||
|
||||
const projectFolderPrompt = prompts.promptQueue.find(
|
||||
item => item.name === 'projectFolder'
|
||||
);
|
||||
projectFolderPrompt.default = (answers) => {
|
||||
// 文件夹名去除scope,如 @coze-arch/foo -> foo
|
||||
// Remove the scope from the folder name, such as @code-arch/foo - > foo
|
||||
const folderDir = answers.packageName.split('/').slice(-1)[0];
|
||||
return `packages/${answers.team}/${folderDir}`
|
||||
return `frontend/packages/${answers.team}/${folderDir}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -13,38 +13,49 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IPlugin, IHooks, IPromptsHookParams } from 'rush-init-project-plugin';
|
||||
|
||||
import type {
|
||||
IPlugin,
|
||||
IHooks,
|
||||
IPromptsHookParams,
|
||||
} from 'rush-init-project-plugin';
|
||||
// FIXME:
|
||||
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
|
||||
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
|
||||
// 未来需要调整为正常的 node_modules 引用方式
|
||||
// According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
|
||||
// The guidelines of this article cannot be correctly resolved to the corresponding module, and a solution has not been found for the time being, so the relative path reference is used here first
|
||||
// Future needs to be adjusted to normal node_modules citation
|
||||
import { createLog } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
|
||||
import { exec } from './utils';
|
||||
|
||||
export default class SetDefaultAuthorPlugin implements IPlugin {
|
||||
private readonly logger = createLog({
|
||||
prefix: SetDefaultAuthorPlugin.name
|
||||
prefix: SetDefaultAuthorPlugin.name,
|
||||
});
|
||||
|
||||
apply(hooks: IHooks): void {
|
||||
hooks.prompts.tap(SetDefaultAuthorPlugin.name, async (prompts: IPromptsHookParams) => {
|
||||
const prompAuthorEmail = prompts.promptQueue.find((r) => r.name === 'authorName');
|
||||
if (prompAuthorEmail) {
|
||||
const userEmail = String(await exec(this.logger, 'git', ['config', '--get', 'user.email']));
|
||||
Object.assign(prompAuthorEmail, {
|
||||
default() {
|
||||
return userEmail;
|
||||
},
|
||||
validate(author: string) {
|
||||
return /@bytedance\.com$/.test(author);
|
||||
}
|
||||
});
|
||||
hooks.prompts.tap(
|
||||
SetDefaultAuthorPlugin.name,
|
||||
async (prompts: IPromptsHookParams) => {
|
||||
const prompAuthorEmail = prompts.promptQueue.find(
|
||||
r => r.name === 'authorName',
|
||||
);
|
||||
if (prompAuthorEmail) {
|
||||
const userEmail = String(
|
||||
await exec(this.logger, 'git', ['config', '--get', 'user.email']),
|
||||
);
|
||||
Object.assign(prompAuthorEmail, {
|
||||
default() {
|
||||
return userEmail;
|
||||
},
|
||||
validate(author: string) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(author);
|
||||
},
|
||||
});
|
||||
|
||||
hooks.answers.tap("authorPrefix", (answers) => {
|
||||
answers.authorPrefix = userEmail.split('@')?.[0] ?? '';
|
||||
});
|
||||
}
|
||||
});
|
||||
hooks.answers.tap('authorPrefix', answers => {
|
||||
answers.authorPrefix = userEmail.split('@')?.[0] ?? '';
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
import type { IHooks, IPlugin, IPromptsHookParams } from 'rush-init-project-plugin';
|
||||
import { parseCommandLineArguments } from './utils/parse-args';
|
||||
|
||||
export default class FornaxPlugin implements IPlugin {
|
||||
apply(hooks: IHooks): void {
|
||||
hooks.answers.tap('FornaxPlugin', (answers) => {
|
||||
if(answers.template === 'fornax-child-app') {
|
||||
if(answers.packageName.startsWith('@flow-devops/fornax-')) {
|
||||
answers.childAppName = answers.packageName.replace('@flow-devops/fornax-','');
|
||||
} else {
|
||||
throw new Error('The initialization of field childAppName failed because the packageName is invalid. Please use "@flow-devops/fornax-xxx."');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
import type { IPlugin, IHooks, ITemplatesHook, IPromptsHookParams } from 'rush-init-project-plugin';
|
||||
// FIXME:
|
||||
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
|
||||
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
|
||||
// 未来需要调整为正常的 node_modules 引用方式
|
||||
import { getTemplatesFolder, getTemplateNameList } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin/lib/logic/templateFolder';
|
||||
import { parseCommandLineArguments } from './utils/parse-args';
|
||||
|
||||
export default class ShowChatAreaTemplatePlugin implements IPlugin {
|
||||
apply(hooks: IHooks): void {
|
||||
const args = parseCommandLineArguments();
|
||||
|
||||
const answer = JSON.parse(args.answer ?? '{}');
|
||||
const isShowChatAreaTemplate = answer['showChatAreaTemplate'];
|
||||
|
||||
hooks.templates.tap("ShowChatAreaTemplatePlugin", (templates: ITemplatesHook) => {
|
||||
const templateFolder: string = getTemplatesFolder();
|
||||
const templateNameList = getTemplateNameList(templateFolder)
|
||||
|
||||
const filteredNormalTemplateNameList = templateNameList.filter(item => !item.templateFolder?.includes('chat-'));
|
||||
|
||||
templates.templates.push(...(isShowChatAreaTemplate ? templateNameList : filteredNormalTemplateNameList ));
|
||||
});
|
||||
}
|
||||
}
|
||||
55
common/_templates/_plugins/ShowTemplatePlugin.ts
Normal file
55
common/_templates/_plugins/ShowTemplatePlugin.ts
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
import type {
|
||||
IPlugin,
|
||||
IHooks,
|
||||
ITemplatesHook,
|
||||
IPromptsHookParams,
|
||||
} from 'rush-init-project-plugin';
|
||||
// FIXME:
|
||||
// According to https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
|
||||
// The guidelines of this article cannot be correctly resolved to the corresponding module, and a solution has not been found for the time being, so the relative path reference is used here first
|
||||
// Future needs to be adjusted to normal node_modules citation
|
||||
import {
|
||||
getTemplatesFolder,
|
||||
getTemplateNameList,
|
||||
} from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin/lib/logic/templateFolder';
|
||||
import { parseCommandLineArguments } from './utils/parse-args';
|
||||
|
||||
export default class ShowTemplatePlugin implements IPlugin {
|
||||
apply(hooks: IHooks): void {
|
||||
const args = parseCommandLineArguments();
|
||||
|
||||
const answer = JSON.parse(args.answer ?? '{}');
|
||||
const isShowChatAreaTemplate = answer['showTemplate'];
|
||||
|
||||
hooks.templates.tap('ShowTemplatePlugin', (templates: ITemplatesHook) => {
|
||||
const templateFolder: string = getTemplatesFolder();
|
||||
const templateNameList = getTemplateNameList(templateFolder);
|
||||
|
||||
const filteredNormalTemplateNameList = templateNameList.filter(
|
||||
item => !item.templateFolder?.includes('chat-'),
|
||||
);
|
||||
|
||||
templates.templates.push(
|
||||
...(isShowChatAreaTemplate
|
||||
? templateNameList
|
||||
: filteredNormalTemplateNameList),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -13,13 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import type { IConfig } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
|
||||
import ShowChatAreaTemplatePlugin from './ShowChatAreaTemplatePlugin';
|
||||
import SetFornaxChildAppPlugin from './SetFornaxChildAppPlugin';
|
||||
import ShowTemplatePlugin from './ShowTemplatePlugin';
|
||||
|
||||
const config: IConfig = {
|
||||
plugins: [new ShowChatAreaTemplatePlugin(), new SetFornaxChildAppPlugin()]
|
||||
plugins: [new ShowTemplatePlugin()],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@ -21,18 +21,18 @@ export function parseCommandLineArguments() {
|
||||
const args = process.argv.slice(2);
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
// 循环遍历所有参数
|
||||
// Loop through all parameters
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
// 检查当前参数是否是一个选项(以 "--" 开头)
|
||||
// Check if the current argument is an option (starting with "--").
|
||||
if (args[i].startsWith('--')) {
|
||||
const key = args[i].substring(2); // 移除 "--" 前缀
|
||||
const key = args[i].substring(2); // Remove the "--" prefix
|
||||
|
||||
// 检查下一个参数是否存在,且不是另一个选项
|
||||
// Check if the next argument exists and is not another option
|
||||
if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
|
||||
result[key] = args[i + 1]; // 将下一个参数作为当前选项的值
|
||||
i++; // 跳过下一个参数,因为它已经被处理为当前选项的值
|
||||
result[key] = args[i + 1]; // Set the next argument as the value of the current option
|
||||
i++; // Skip the next argument because it has already been processed to the value of the current option
|
||||
} else {
|
||||
result[key] = ''; // 如果没有值,只设置选项的键
|
||||
result[key] = ''; // If there is no value, only set the key of the option
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
import { mergeConfig } from 'vite';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
viteFinal: config =>
|
||||
mergeConfig(config, {
|
||||
plugins: [
|
||||
svgr({
|
||||
svgrOptions: {
|
||||
native: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
};
|
||||
export default config;
|
||||
@ -1,14 +0,0 @@
|
||||
/** @type { import('@storybook/react').Preview } */
|
||||
const preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@ -1,5 +0,0 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user