fix: fix skill workspace directory

This commit is contained in:
alan.cl
2026-03-22 17:27:06 +08:00
parent f19450e9d4
commit 681a3ee5e0
26 changed files with 248 additions and 68 deletions

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-acc-auto"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -2,7 +2,7 @@
# https://github.com/astral-sh/uv/issues/2252#issuecomment-2624150395
[project]
name = "dbgpt-acc-flash-attn"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.10"

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-app"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }
@@ -64,3 +64,21 @@ exclude = [
"src/dbgpt_app/**/examples/*"
]
[tool.hatch.build.targets.sdist.force-include]
"../../skills/csv-data-analysis" = "skills/csv-data-analysis"
"../../skills/skill-creator" = "skills/skill-creator"
"../../skills/financial-report-analyzer" = "skills/financial-report-analyzer"
"../../skills/walmart-sales-analyzer" = "skills/walmart-sales-analyzer"
"../../skills/agent-browser" = "skills/agent-browser"
"../../docker/examples/excel/Walmart_Sales.csv" = "examples/excel/Walmart_Sales.csv"
"../../docker/examples/fin_report/pdf/2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf" = "examples/fin_report/pdf/2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf"
[tool.hatch.build.targets.wheel.force-include]
"skills/csv-data-analysis" = "dbgpt_app/_builtin_skills/csv-data-analysis"
"skills/skill-creator" = "dbgpt_app/_builtin_skills/skill-creator"
"skills/financial-report-analyzer" = "dbgpt_app/_builtin_skills/financial-report-analyzer"
"skills/walmart-sales-analyzer" = "dbgpt_app/_builtin_skills/walmart-sales-analyzer"
"skills/agent-browser" = "dbgpt_app/_builtin_skills/agent-browser"
"examples/excel/Walmart_Sales.csv" = "dbgpt_app/_builtin_examples/excel/Walmart_Sales.csv"
"examples/fin_report/pdf/2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf" = "dbgpt_app/_builtin_examples/fin_report/pdf/2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf"

View File

@@ -0,0 +1,7 @@
"""Builtin example files bundled with the dbgpt-app wheel.
This package exists solely as an anchor so that code can locate the
bundled example data files via ``os.path.dirname(__file__)``.
The actual data files are injected by hatch ``force-include`` at build
time and are **not** present during source-code development.
"""

View File

@@ -0,0 +1,6 @@
"""Builtin skills bundled with dbgpt-app.
These skills are copied into the user's skills directory (~/.dbgpt/skills/)
on first startup via ``ensure_builtin_skills()``. Do **not** modify files
in this directory directly -- they will be overwritten on package upgrade.
"""

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -124,6 +124,12 @@ def _migration_db_storage(
# dest_root is the parent of meta_data/ (e.g. ~/.dbgpt/workspace/pilot/)
pilot_root = os.path.dirname(default_meta_data_path)
_ensure_pilot_workspace(pilot_root)
# Provision builtin skills for pip-installed users.
from dbgpt.configs.model_config import SKILLS_DIR
from dbgpt_app.initialization.skills_provisioning import ensure_builtin_skills
ensure_builtin_skills(SKILLS_DIR)
if not disable_alembic_upgrade:
from dbgpt.storage.metadata.db_manager import db
from dbgpt.util._db_migration_utils import _ddl_init_and_upgrade

View File

@@ -89,10 +89,11 @@ def mount_routers(app: FastAPI):
def mount_static_files(app: FastAPI, param: ApplicationConfig):
package_dir = os.path.dirname(os.path.abspath(__file__))
if param.service.web.new_web_ui:
static_file_path = os.path.join(ROOT_PATH, "src", "dbgpt_app/static/web")
static_file_path = os.path.join(package_dir, "static", "web")
else:
static_file_path = os.path.join(ROOT_PATH, "src", "dbgpt_app/static/old_web")
static_file_path = os.path.join(package_dir, "static", "old_web")
os.makedirs(STATIC_MESSAGE_IMG_PATH, exist_ok=True)
app.mount(
@@ -172,25 +173,37 @@ def initialize_app(param: ApplicationConfig, args: List[str] = None):
# Register default data sources
try:
from dbgpt.configs.model_config import ROOT_PATH
from dbgpt.configs.model_config import PILOT_PATH, ROOT_PATH
from dbgpt_serve.datasource.manages.connect_config_db import ConnectConfigDao
dao = ConnectConfigDao()
db_name = "Walmart_Sales"
if not dao.get_by_names(db_name):
db_absolute_path = os.path.join(
ROOT_PATH, "docker/examples/dashboard/Walmart_Sales.db"
)
dao.add_file_db(
db_name=db_name,
db_type="sqlite",
db_path=db_absolute_path,
comment="Default Walmart Sales example database",
)
logger.info(
f"Successfully registered default data source: "
f"{db_name} at {db_absolute_path}"
candidate_paths = [
os.path.join(PILOT_PATH, "examples", "Walmart_Sales.db"),
os.path.join(
ROOT_PATH, "docker", "examples", "dashboard", "Walmart_Sales.db"
),
]
db_absolute_path = next(
(p for p in candidate_paths if os.path.isfile(p)), None
)
if db_absolute_path is None:
logger.info(
f"Skipping default data source '%s': file not found in any "
f"{db_name} at {candidate_paths}"
)
else:
dao.add_file_db(
db_name=db_name,
db_type="sqlite",
db_path=db_absolute_path,
comment="Default Walmart Sales example database",
)
logger.info(
f"Successfully registered default data source: "
f"{db_name} at {db_absolute_path}"
)
except Exception as e:
logger.error(f"Failed to register default data sources: {str(e)}")

View File

@@ -0,0 +1,68 @@
"""Skills provisioning module for dbgpt-app pip package users.
Copies builtin skill templates from the installed package to the user's
skills directory on first startup. Existing skills are never overwritten.
"""
import logging
import os
import shutil
logger = logging.getLogger(__name__)
def ensure_builtin_skills(skills_dir: str) -> None:
"""Idempotently seed builtin skills into *skills_dir*.
On first run after ``pip install dbgpt-app``, the builtin skill
templates bundled inside the wheel (``dbgpt_app/_builtin_skills/``)
are copied to *skills_dir*. Skills that already exist in the
destination are **never** overwritten so that user modifications are
preserved.
This function is a no-op when:
* ``dbgpt_app._builtin_skills`` cannot be imported (e.g. running
from a source checkout where the force-include hasn't been
triggered).
* The builtin skills directory inside the package is empty.
Args:
skills_dir: Absolute path to the target skills directory,
e.g. ``~/.dbgpt/skills/``.
"""
try:
import dbgpt_app._builtin_skills as _bs
builtin_root = os.path.dirname(_bs.__file__)
except (ImportError, AttributeError):
logger.debug("dbgpt_app._builtin_skills not available, skipping seed.")
return
if not os.path.isdir(builtin_root):
return
os.makedirs(skills_dir, exist_ok=True)
for entry in os.listdir(builtin_root):
# Skip Python artifacts and hidden files
if entry.startswith(("_", ".")) or entry == "__pycache__":
continue
src = os.path.join(builtin_root, entry)
dst = os.path.join(skills_dir, entry)
# Never overwrite existing skills (user may have modified them)
if os.path.exists(dst):
logger.debug("Builtin skill already exists, skipping: %s", dst)
continue
if os.path.isdir(src):
shutil.copytree(src, dst)
logger.info("Provisioned builtin skill: %s", entry)
else:
shutil.copy2(src, dst)
logger.info("Provisioned builtin skill file: %s", entry)
# Ensure user/ subdirectory exists for uploaded/imported skills
user_dir = os.path.join(skills_dir, "user")
os.makedirs(user_dir, exist_ok=True)

View File

@@ -19,7 +19,7 @@ from dbgpt._private.pydantic import BaseModel as _BaseModel
from dbgpt.agent.resource.tool.base import tool
from dbgpt.agent.skill.manage import get_skill_manager
from dbgpt.component import ComponentType
from dbgpt.configs.model_config import resolve_root_path
from dbgpt.configs.model_config import SKILLS_DIR, resolve_root_path
from dbgpt.core import PromptTemplate
from dbgpt.model.cluster import WorkerManagerFactory
from dbgpt_app.openapi.api_view_model import (
@@ -38,7 +38,7 @@ if TYPE_CHECKING:
REACT_AGENT_MEMORY_CACHE: Dict[str, "GptsMemory"] = {}
DEFAULT_SKILLS_DIR = resolve_root_path("skills") or "skills"
DEFAULT_SKILLS_DIR = SKILLS_DIR
AUTO_DATA_MARKER_PATTERN = re.compile(
r"###([A-Z0-9_]+)_START###\s*(.*?)\s*###\1_END###", re.DOTALL
)

View File

@@ -1,6 +1,19 @@
"""API endpoints for bundled example files.
Provides a single ``POST /v1/examples/use`` endpoint that copies a bundled
example file to the user's upload directory so it can be used in
conversations.
Example files are resolved in the following order:
1. ``docker/examples/`` under the source-code project root (dev mode).
2. ``dbgpt_app/_builtin_examples/`` inside the installed wheel (PyPI mode).
"""
import logging
import os
import shutil
from typing import Optional
from fastapi import APIRouter, Body, Depends
@@ -12,32 +25,78 @@ router = APIRouter()
CFG = Config()
logger = logging.getLogger(__name__)
# Map of example IDs to their file paths (relative to project root)
# Map of example IDs to their file info.
# - ``source_path``: path relative to source-repo root (``docker/examples/…``).
# - ``builtin_path``: path relative to ``_builtin_examples/`` inside the wheel.
# - ``name``: the user-visible filename.
EXAMPLE_FILES = {
"walmart_sales": {
"path": "docker/examples/excel/Walmart_Sales.csv",
"source_path": "docker/examples/excel/Walmart_Sales.csv",
"builtin_path": "excel/Walmart_Sales.csv",
"name": "Walmart_Sales.csv",
},
"csv_visual_report": {
"path": "docker/examples/excel/Walmart_Sales.csv",
"source_path": "docker/examples/excel/Walmart_Sales.csv",
"builtin_path": "excel/Walmart_Sales.csv",
"name": "Walmart_Sales.csv",
},
"fin_report": {
"path": (
"source_path": (
"docker/examples/fin_report/pdf/"
"2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf"
),
"builtin_path": (
"fin_report/pdf/"
"2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf"
),
"name": (
"2020-01-23__浙江海翔药业股份有限公司__002099__海翔药业__2019年__年度报告.pdf"
),
},
"create_sql_skill": {
"path": "docker/examples/txt/sql_skill.txt",
"source_path": "docker/examples/txt/sql_skill.txt",
"builtin_path": "txt/sql_skill.txt",
"name": "sql_skill.txt",
},
}
def _resolve_example_source(example: dict) -> Optional[str]:
"""Return the absolute path to an example file, or *None* if not found.
Resolution order:
1. ``docker/examples/…`` under ``SYSTEM_APP.work_dir`` or cwd (source-code
development mode).
2. ``_builtin_examples/…`` inside the installed ``dbgpt_app`` package
(PyPI install mode).
"""
# --- 1. Source-code / work_dir mode ---
base_dir = os.getcwd()
if (
CFG.SYSTEM_APP
and hasattr(CFG.SYSTEM_APP, "work_dir")
and CFG.SYSTEM_APP.work_dir
):
base_dir = CFG.SYSTEM_APP.work_dir
candidate = os.path.join(base_dir, example["source_path"])
if os.path.isfile(candidate):
return candidate
# --- 2. Builtin examples bundled in the wheel ---
try:
import dbgpt_app._builtin_examples as _be
builtin_root = os.path.dirname(_be.__file__)
candidate = os.path.join(builtin_root, example["builtin_path"])
if os.path.isfile(candidate):
return candidate
except (ImportError, AttributeError):
pass
return None
@router.post("/v1/examples/use", response_model=Result[str])
async def use_example_file(
example_id: str = Body(..., embed=True),
@@ -51,7 +110,11 @@ async def use_example_file(
example = EXAMPLE_FILES[example_id]
user_id = user_token.user_id or "default"
# Determine base directory
source_path = _resolve_example_source(example)
if source_path is None:
return Result.failed(msg=f"Example file not found: {example['name']}")
# Determine upload base directory (same convention as python_upload_api)
base_dir = os.getcwd()
if (
CFG.SYSTEM_APP
@@ -60,28 +123,6 @@ async def use_example_file(
):
base_dir = CFG.SYSTEM_APP.work_dir
# Source file - try base_dir first, then project root
source_path = os.path.join(base_dir, example["path"])
if not os.path.exists(source_path):
project_root = os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(__file__))
)
)
)
)
)
)
source_path = os.path.join(project_root, example["path"])
if not os.path.exists(source_path):
return Result.failed(msg=f"Example file not found: {example['name']}")
# Target directory - same as python_upload_api
upload_dir = os.path.join(base_dir, "python_uploads", user_id)
os.makedirs(upload_dir, exist_ok=True)

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-client"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = """DB-GPT is an experimental open-source project that uses localized GPT \
large models to interact with your data and environment. With this solution, you can be\
assured that there is no risk of data leakage, and your data is 100% private and secure.\

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -523,14 +523,9 @@ class SkillManager(BaseComponent):
if hasattr(metadata, "path"):
return metadata.path
skills_dir = os.environ.get("DBGPT_SKILLS_DIR")
if not skills_dir:
from dbgpt.configs.model_config import resolve_root_path
from dbgpt.configs.model_config import SKILLS_DIR
skills_dir = resolve_root_path("skills")
if not skills_dir:
skills_dir = "skills"
skills_dir = SKILLS_DIR
# Search candidate subdirectories: direct, user/, claude/, project/, etc.
subdirs = ["", "user", "claude", "project"]

View File

@@ -375,3 +375,29 @@ KNOWLEDGE_CACHE_ROOT_PATH = os.path.join(
KNOWLEDGE_UPLOAD_ROOT_PATH, "_knowledge_cache_"
)
BENCHMARK_DATA_ROOT_PATH = os.path.join(PILOT_PATH, "benchmark_meta_data")
def _detect_skills_dir() -> str:
"""Detect the skills directory path.
Priority:
1. ``DBGPT_SKILLS_DIR`` environment variable (highest)
2. ``{ROOT_PATH}/skills`` if it exists (source checkout)
3. ``~/.dbgpt/skills`` (pip install mode)
Returns:
str: Absolute path to the skills directory.
"""
env_dir = os.environ.get("DBGPT_SKILLS_DIR")
if env_dir:
return env_dir
source_dir = os.path.join(ROOT_PATH, "skills")
if os.path.isdir(source_dir):
return source_dir
home = os.environ.get("DBGPT_HOME", os.path.expanduser("~/.dbgpt"))
return os.path.join(home, "skills")
SKILLS_DIR = _detect_skills_dir()

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-ext"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-sandbox"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "A secure sandbox execution environment for DB-GPT Agent"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-serve"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = "Add your description here"
authors = [
{ name = "csunny", email = "cfqcsunny@gmail.com" }

View File

@@ -1 +1 @@
version = "0.8.0rc1"
version = "0.8.0rc5"

Binary file not shown.

View File

@@ -1,6 +1,6 @@
[project]
name = "dbgpt-mono"
version = "0.8.0rc1"
version = "0.8.0rc5"
description = """DB-GPT is an experimental open-source project that uses localized GPT \
large models to interact with your data and environment. With this solution, you can be\
assured that there is no risk of data leakage, and your data is 100% private and secure.\