V3.5 精细化运营升级:用量统计/接口库/团队/对话/工作目录/流式超时

1. 精细化统计:cost_records 新增 calls/cached_tokens/latency_ms/first_token_ms;
   用量明细报表(项目×智能体矩阵) + 成本报表细化(输入/输出/缓存命中/调用次数)
2. 从参考项目中新建:内置3个测试项目(文案/Python/调研),一键复制目标+任务
3. 大模型接口库(llm_endpoints):专门配置接口(地址/密钥/模型/定价),
   计费支持按token(逐模型)与按调用次数;创建AI Worker直接选用;
   AI Worker团队(worker_teams):打包Worker,对话/建项目可直接选团队
4. 对话导航融合仪表盘:可选大模型/AI Worker/团队,默认主力AI Worker(可设),SSE流式
5. 系统工作目录:默认data/workspace可改绝对路径;项目与多Agent协作均在其下
   建唯一工作目录;手动输入目录已存在则列出信息并需手动确认
6. 任务执行超时改为流式单token返回超时+首字延迟超时,设置页可配;
   所有模型输出SSE按token接收
This commit is contained in:
2026-09-05 15:27:43 +08:00
parent 339dd89ba6
commit c56745a8ab
13 changed files with 2231 additions and 197 deletions
+82 -6
View File
@@ -18,9 +18,9 @@ from email.mime.application import MIMEApplication
from email.utils import formataddr
import db
from config import DATA_DIR, EMAIL, PUBLIC_BASE_URL
from config import DATA_DIR, EMAIL, PUBLIC_BASE_URL, DEFAULT_WORKSPACE_ROOT
WORKSPACE_ROOT = os.path.join(DATA_DIR, 'workspace')
WORKSPACE_ROOT = DEFAULT_WORKSPACE_ROOT
DEMO_ROOT = os.path.join(DATA_DIR, 'demo')
PACKAGE_ROOT = os.path.join(DATA_DIR, 'packages')
@@ -29,14 +29,70 @@ BLOCKER_DEDUP_SECONDS = 1800
def ensure_dirs():
for d in (WORKSPACE_ROOT, DEMO_ROOT, PACKAGE_ROOT):
for d in (DEMO_ROOT, PACKAGE_ROOT):
os.makedirs(d, exist_ok=True)
os.makedirs(get_workspace_root(), exist_ok=True)
def get_workspace_root():
"""系统工作目录(V3.5):默认 data/workspace,可在设置中改成任意绝对路径(无则创建,已存在需确认)。
所有项目工作目录与多 Agent 协作工作目录都建在此目录下。"""
root = (db.get_setting('sys_workspace_root', '') or '').strip() or WORKSPACE_ROOT
if not os.path.isabs(root):
root = os.path.join(DATA_DIR, root.lstrip('/'))
try:
os.makedirs(root, exist_ok=True)
except Exception:
root = WORKSPACE_ROOT
os.makedirs(root, exist_ok=True)
return root
def dir_info(path):
"""已存在目录的相关信息:文件数 / 总大小 / 最近修改 / 样例列表(供确认提醒)。不存在返回 None。"""
if not path or not os.path.isdir(path):
return None
n = total = 0
newest = 0
sample = []
try:
for dirpath, dirnames, filenames in os.walk(path):
dirnames[:] = [d for d in dirnames if not d.startswith('.')]
for fn in sorted(filenames):
if fn.startswith('.'):
continue
full = os.path.join(dirpath, fn)
try:
st = os.stat(full)
except OSError:
continue
n += 1
total += st.st_size
if st.st_mtime > newest:
newest = st.st_mtime
if len(sample) < 40:
sample.append(os.path.relpath(full, path))
except Exception:
pass
return {'exists': True, 'path': path, 'files': n, 'size': total,
'newest_mtime': int(newest), 'sample': sample}
def workspace_path(project):
"""项目工作目录绝对路径(不存在则创建)"""
pid = project['id'] if isinstance(project, dict) else project
d = os.path.join(WORKSPACE_ROOT, f'project_{pid}')
"""项目工作目录绝对路径(V3.5:支持自定义 workspace_dir,相对系统工作目录或绝对路径;不存在则创建)"""
if isinstance(project, dict):
p = project
pid = p['id']
else:
pid = project
p = db.q('SELECT workspace_dir FROM projects WHERE id=?', (pid,), one=True)
wd = ((p or {}).get('workspace_dir') or '').strip() if p else ''
if not wd:
wd = f'project_{pid}'
if os.path.isabs(wd):
d = wd
else:
d = os.path.join(get_workspace_root(), wd)
os.makedirs(d, exist_ok=True)
return d
@@ -52,6 +108,26 @@ def package_dir():
return PACKAGE_ROOT
def agent_workspace(run_id):
"""多 Agent 协作运行的工作目录:在系统工作目录下新建 agent_run_<id>(唯一,不存在则创建)"""
d = os.path.join(get_workspace_root(), f'agent_run_{run_id}')
os.makedirs(d, exist_ok=True)
return d
def write_agent_context(run_id, topic, context=''):
"""在协作运行工作目录写入运行说明文件"""
d = agent_workspace(run_id)
try:
with open(os.path.join(d, 'run_context.md'), 'w', encoding='utf-8') as fh:
fh.write(f'# 多 Agent 协作运行 #{run_id}\n\n')
fh.write(f'## 主题\n{topic}\n\n')
fh.write(f'## 背景上下文\n{context or "(无)"}\n')
except Exception:
pass
return d
def _safe_relpath(relpath):
"""路径穿越防护:仅允许工作目录内的相对路径"""
relpath = (relpath or '').replace('\\', '/').strip('/')