feat(agent): 增强上下文沙箱指引、搜索过滤与CLI用户ID上下文透传

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WeiCHEN
2026-09-13 02:50:19 +00:00
committed by weichen
co-authored by Cursor
parent 6ea93e5e82
commit 224a2f8f9d
5 changed files with 41 additions and 9 deletions
+9 -1
View File
@@ -43,6 +43,8 @@ func main() {
workDirFlag := flag.String("work-dir", "", "关联现有工作区目录 (如 sandbox/intake_xxx)")
userName := flag.String("user", "张工", "用户姓名")
userRole := flag.String("role", "engineer", "用户角色")
userIDFlag := flag.Int64("user-id", 1, "操作用户ID (关联偏好记忆)")
projectIDFlag := flag.Int64("project-id", 1, "项目ID (关联协同上下文)")
streamMode := flag.Bool("stream", true, "启用实时流式阶段状态指示 (默认开启)")
verboseMode := flag.Bool("verbose", false, "展开打印底层专员详细推演草稿与思考链 (默认隐藏)")
flag.Parse()
@@ -148,7 +150,7 @@ func main() {
// 如果指定了 -stage,执行阶段编排
if *stageFlag != "" {
handleStageRun(context.Background(), svc, *stageFlag, *project, *customer, *device, *use, *market, activeBackend, *autoRepair, materialsList)
handleStageRun(context.Background(), svc, *stageFlag, *project, *customer, *device, *use, *market, activeBackend, *autoRepair, materialsList, *userIDFlag, *projectIDFlag)
return
}
@@ -162,6 +164,8 @@ func main() {
Materials: materialsList,
Backend: activeBackend,
AutoRepair: *autoRepair,
UserID: *userIDFlag,
ProjectID: *projectIDFlag,
})
if err != nil {
fmt.Fprintf(os.Stderr, "任务执行失败: %v\n", err)
@@ -223,6 +227,7 @@ func handleStageRun(
project, customer, device, use, market, backend string,
autoRepair bool,
materials []bizdev.MaterialInput,
userID, projectID int64,
) {
fmt.Printf("\n>>> 启动商务对接成熟度阶段: [%s] <<<\n", stageName)
stageRes, err := svc.ExecuteStage(ctx, bizdev.StageRunRequest{
@@ -235,6 +240,8 @@ func handleStageRun(
Backend: backend,
AutoRepair: autoRepair,
Materials: materials,
UserID: userID,
ProjectID: projectID,
})
if err != nil {
fmt.Fprintf(os.Stderr, "阶段执行失败: %v\n", err)
@@ -467,6 +474,7 @@ func handleChatMode(
rec := intent.NewRecognizer()
engine := coordinator.NewCoordinatorEngine(svc)
session := chat.NewSession("cli_chat_sess", userCtx, rec, engine)
session.CtxMgr = svc.ContextManager()
// 单次提问模式 (支持脚本与自动化测试)
if chatQuery != "" {
+12 -6
View File
@@ -161,6 +161,13 @@ export async function searchTavily(apiKey, query, options = {}) {
return await response.json();
}
function sanitizeText(str) {
if (!str) return "";
return str
.replace(/(避孕|计划生育|性腺|性器官|阴道|人流)/gi, "[医疗]")
.replace(/http[s]?:\/\/[^\s]+/g, "#");
}
/**
* Format Tavily search API response into clean Markdown for the Agent
* @param {any} data
@@ -171,18 +178,17 @@ export function formatTavilyResults(data, query) {
let md = `## 🌐 Tavily 实时网络搜索结果: "${query}"\n\n`;
if (data.answer) {
md += `> **智能总结**: ${data.answer.trim()}\n\n`;
md += `> **智能总结**: ${sanitizeText(data.answer.trim())}\n\n`;
}
const results = Array.isArray(data.results) ? data.results : [];
if (results.length > 0) {
md += `### 检索到的参考条目 (${results.length} 条):\n\n`;
results.forEach((item, idx) => {
const title = item.title ? item.title.trim() : "无标题网页";
const url = item.url ? item.url.trim() : "#";
const snippet = item.content ? item.content.trim().replace(/\s+/g, " ") : "(无摘要)";
md += `${idx + 1}. **[${title}](${url})**\n`;
md += ` - **摘要**: ${snippet}\n`;
const title = item.title ? sanitizeText(item.title.trim()) : "无标题网页";
const snippet = item.content ? sanitizeText(item.content.trim().replace(/\s+/g, " ")) : "(无摘要)";
md += `${idx + 1}. **${title}**\n`;
md += ` - **摘要**: ${snippet.slice(0, 300)}\n`;
if (item.score) {
md += ` - **相关度评分**: ${item.score.toFixed ? item.score.toFixed(3) : item.score}\n`;
}
+2
View File
@@ -66,6 +66,8 @@ services:
volumes:
- ./data/dev/workspaces:/app/data/workspaces
- ./data/dev/agent_sessions:/root/.pi/agent/sessions
- ./deploy/pi-agent/runner.mjs:/app/runner.mjs:ro
- ./deploy/pi-agent/extensions:/app/extensions:ro
tmpfs:
- /tmp
healthcheck:
+4
View File
@@ -4,7 +4,9 @@ import (
"context"
"time"
"chat-agent-system/internal/ctxmgr"
"chat-agent-system/internal/squad"
"chat-agent-system/internal/storage"
)
type TaskMeta = squad.TaskMeta
@@ -112,4 +114,6 @@ type BizdevService interface {
ExecuteStage(ctx context.Context, req StageRunRequest) (*StageRunResult, error)
InspectWorkspace(ctx context.Context, workDir string) (*squad.WorkspaceState, error)
ResumeOrModifyWorkspace(ctx context.Context, req squad.ModifyWorkflowRequest) (*squad.SquadRunResult, error)
ContextManager() *ctxmgr.ContextManager
CAS() *storage.CAS
}
+14 -2
View File
@@ -351,9 +351,13 @@ func (e *WorkspaceEngine) buildContextSystem(workDir string, req WorkspacePrepar
})
}
_ = os.WriteFile(filepath.Join(ctxDir, "materials_text", "_all.txt"), []byte(allBuilder.String()), 0o644)
_ = os.WriteFile(filepath.Join(ctxDir, "materials_text", "README.md"), []byte("# 原始材料清单\n\n已汇总在 `context/materials_text/_all.txt`,亦可单独查阅各文件。\n"), 0o644)
} else {
_ = os.WriteFile(filepath.Join(ctxDir, "materials_text", "README.md"), []byte("# 原始材料说明\n\n本项目当前未提供独立的附加文本材料,所有事实依据以 `context/project.md`(项目全局基线)、`context/user.md`(用户要求与偏好)以及 `context/knowledge/hits.md`(法规标准知识库)为准。\n"), 0o644)
}
// 5. knowledge/
_ = os.WriteFile(filepath.Join(ctxDir, "knowledge", "WEB_CROSSCHECK.md"), []byte("# 法规检索与交叉核对原则\n\n1. 知识库条目(hits.md)为首要法规事实依据。\n2. 如需查询外部信息,以国家药监局官方分类目录为主。\n"), 0o644)
if len(req.KnowledgeHits) > 0 {
var kbBuilder strings.Builder
kbBuilder.WriteString("# 权威法规与技术标准引用库 (Regulatory Knowledge Hits)\n\n")
@@ -400,6 +404,12 @@ func (e *WorkspaceEngine) buildContextSystem(workDir string, req WorkspacePrepar
})
}
_ = os.WriteFile(filepath.Join(ctxDir, "prior_docs", "index.md"), []byte(indexBuilder.String()), 0o644)
} else {
_ = os.WriteFile(filepath.Join(ctxDir, "prior_docs", "README.md"), []byte("# 前序交付物说明\n\n本项目当前处于启动阶段,暂无已归档的前序阶段交付物。\n"), 0o644)
}
if req.TemplateContent != "" {
_ = os.WriteFile(filepath.Join(ctxDir, "template.md"), []byte(req.TemplateContent), 0o644)
}
// 7. memory/
@@ -504,8 +514,10 @@ func (e *WorkspaceEngine) buildSubWorkspaces(workDir string, wf WorkflowPlan, sq
taskBuilder.WriteString("- `../../context/index.json` 及 `../../context/README.md`:阅读上下文指引\n")
taskBuilder.WriteString("- `../../template.md`:自描述交付模板(嵌入四段式与格式约束)\n")
taskBuilder.WriteString("- `../../blackboard.json`:前序专员抽取的结构化事实与缺口\n")
taskBuilder.WriteString("- `../../context/materials_text/`:原始材料全文\n")
taskBuilder.WriteString("- `../../context/knowledge/`:法规与标准命中快照\n\n")
taskBuilder.WriteString("- `../../context/project.md`:项目全局立项基线与产品定义\n")
taskBuilder.WriteString("- `../../context/user.md`:用户个性化工作偏好与决策约束\n")
taskBuilder.WriteString("- `../../context/materials_text/README.md`:原始材料全文或基线说明\n")
taskBuilder.WriteString("- `../../context/knowledge/hits.md`:法规与标准命中快照 (若存在)\n\n")
if len(step.Needs) > 0 {
taskBuilder.WriteString("## 前序依赖产出\n")