mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 10:11:58 +00:00
dcadc0c48b
三条 run(d983c4e6 / 14103db5 / 08c3de1c)在用户看来是一次对话,系统里却
毫无关联。查下来不是哪里传漏了,是整层缺失:
- 每轮 base_graph=None 从零建图,Copilot 不知道上一轮问过什么
- 每轮 thread_id = run.id,三条独立的 checkpoint 线程
- 前端 turns 只活在 zustand 里,刷新页面就全没了——那三轮当时在界面上
已经找不回来,只剩 runs 表里三条互不相干的记录
- 后端 13 张表里没有会话这个概念
加两张表(conversations / conversation_turns)。失败的轮次也记:只记成功的,
历史就成了一份美化过的记录,而人回来最想搞清楚的恰恰是上次卡在哪。
Copilot 的上下文带三样:前几轮问答、上一轮那张图(走 _slim 去掉坐标噪音)。
只给问答文字不够——"再按月份拆一下"会让模型重新设计一张图,实测经常接到另
一张表上,答案对不上前一轮。运行时另外注入 {{ input.history }},管的是指代:
用户问"它们平均多少",图里的 agent 得知道"它们"是上一轮那 12 家店。
左侧会话栏只在问数据页出现,可折叠、可改名删除,当前会话存 localStorage。
轮次按会话分桶缓存——切走再切回来要看得到原来的步骤,回源只拿得到问答。
历史轮次的执行过程不预加载,点「看执行过程」才取事件、走现成的 decodeRun。
画布右栏的 Copilot 依附工作流各有一条会话,连说两次"再加一个节点"能接上了
(base_graph 带的是图的结果,带不出"你刚才要我干什么"),但不进左侧列表。
过程中修掉的两个自己引入的坑:
- 第一版在列表为空时自动建一条会话。create 是异步的、StrictMode 把 effect
跑两遍,于是每次进页面都留下两三条"新对话"。改成用户开口那一刻按需建
- 加了"在上一轮的图上改"这条指令之后,模型照改图协议只发 update_node,
而问数据页这条路径的累加器从空图起步,操作全部落空,用户收到的是
"图校验未通过:图是空的,先拖一个节点进来"(会话 f5db9809 的第二轮,
而它的 explanation 证明上下文其实完全读懂了)。指令改成沿用 id 和 config
但完整重发,另加一道兜底:空图且上一轮有图时把操作重放到那张图上
check-ui 多一节「会话」:切换、刷新还在、逛一圈不多出空会话。
92 lines
2.3 KiB
Python
92 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
from typing import AsyncIterator
|
|
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from app.api import (
|
|
artifacts, conversations, copilot, datasources, governance, knowledge, runs,
|
|
sandbox, settings as settings_api, tools, workflows,
|
|
)
|
|
from app.core.config import settings
|
|
from app.db.base import init_db
|
|
from app.engine.runner import run_manager
|
|
from app.seed import seed_defaults
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s %(levelname)-7s %(name)s | %(message)s",
|
|
datefmt="%H:%M:%S",
|
|
)
|
|
logger = logging.getLogger("agentlab")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
|
|
settings.ensure_dirs()
|
|
await init_db()
|
|
await seed_defaults()
|
|
await run_manager.setup()
|
|
from app.sandbox.manager import sandbox_manager as _sbm
|
|
|
|
await _sbm.start_reaper()
|
|
logger.info("AgentLab 就绪 · 数据目录 %s", settings.data_dir)
|
|
try:
|
|
yield
|
|
finally:
|
|
await run_manager.shutdown()
|
|
from app.sandbox.manager import sandbox_manager
|
|
|
|
await sandbox_manager.close()
|
|
logger.info("已停止")
|
|
|
|
|
|
app = FastAPI(
|
|
title="AgentLab",
|
|
description="可视化 Agent 编排实验台",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.cors_origins,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
for router in (
|
|
workflows.router,
|
|
runs.router,
|
|
runs.approvals_router,
|
|
settings_api.router,
|
|
tools.router,
|
|
tools.custom_router,
|
|
tools.mcp_router,
|
|
knowledge.memory_router,
|
|
knowledge.kb_router,
|
|
knowledge.skills_router,
|
|
sandbox.router,
|
|
copilot.router,
|
|
conversations.router,
|
|
artifacts.router,
|
|
governance.router,
|
|
datasources.router,
|
|
):
|
|
app.include_router(router)
|
|
|
|
|
|
@app.exception_handler(ValueError)
|
|
async def value_error_handler(_: Request, exc: ValueError) -> JSONResponse:
|
|
return JSONResponse(status_code=400, content={"detail": str(exc)})
|
|
|
|
|
|
@app.get("/api/health")
|
|
async def health() -> dict[str, str]:
|
|
return {"status": "ok", "service": "agentlab"}
|