feat(agent): align investigation reports and selected context
This commit is contained in:
@@ -33,8 +33,8 @@ export const buildAgentTriggerPrompt = (trigger: AgentTriggerContext) => [
|
||||
event_id: trigger.trigger_id,
|
||||
})}</external_work_order>`,
|
||||
"这是合成演练数据,不得表述为生产事实。",
|
||||
"根据这张工单的事实动态规划本次调查,不套用预设路线。开始调查前调用 publish_execution_plan 发布 execution-plan@2,明确路线选择、并行分叉与汇合、人工审核点;执行前、取得结果后、遇到阻塞或修改计划时再次发布完整快照。保留节点 ID、已完成节点及证据,重试用新节点,不要按时间推算进度。",
|
||||
"每个完成节点必须列明实际依据。预设证据标注为合成场景输入,不得声称执行过未调用的数据查询工具。现场采样、清洗、复测、回访等人工工作保持 waiting,写清等待内容,不得因回复结束标记完成。",
|
||||
"根据这张工单的事实动态规划本次调查,不套用预设路线。先读取 get_operational_task_context,自主查询授权数据并保存证据和调查报告;todo、Mermaid 和可选的旧计划仅向人解释,不约束执行或决定任务完成。数据权限由系统配置,人工审核仅针对具体工单或设备命令。",
|
||||
"每项判断必须列明实际依据。预设证据标注为合成场景输入,不得声称执行过未调用的数据查询工具。关键数据不足时发布 final/insufficient_data 报告,记录 stop_reason 和有查询依据的阻塞 data_gaps,清空 recommendations 与 pending_items,正常结束本轮;权限拒绝和接口错误不能证明数据缺失。现场采样、清洗、复测及回访是否完成以外部反馈为准,未来人工工作不阻止本轮调查结束。",
|
||||
"外围样板随事件提供的合成场景输入(不是 Agent 实时查询结果):上游三个模拟水质监测点的数据质量均为 valid,演示指标均在场景阈值内,且相邻片区没有同类投诉;投诉集中在演示小区,二次供水水箱最近一次清洗记录待核验。",
|
||||
"依据实际取得的证据判断可能原因,区分合成场景输入、已查询数据和待现场核验事项;给出处置、复测和回访建议。不得将疑似判断写成已确认事故。",
|
||||
"依据实际取得的证据判断可能原因,区分合成场景输入、已查询数据和待现场核验事项。已形成判断时可给出处置建议;提议具体动作前先保存 interim/concluded 报告,提议成功后再保存 final 报告。不得将疑似判断写成已确认事故。",
|
||||
].join("\n");
|
||||
|
||||
@@ -106,7 +106,7 @@ export const registerChatSessionRoutes = (
|
||||
body: JSON.stringify({
|
||||
session_id: record.sessionId,
|
||||
model,
|
||||
message: `执行工况任务${workflow ? `:${workflow}` : ""}。先读取后端任务上下文,依据当前工单或人工请求动态规划 execution-plan@2;按实际选择的路线更新计划、证据和报告,数据权限不足时先申请并等待审核。`,
|
||||
message: `执行工况任务${workflow ? `:${workflow}` : ""}。先读取后端任务上下文,自主查询并保存证据和调查报告;可在报告内用 Mermaid 调查图向人解释方向、分支和依据,图及 todo 均不约束执行。数据权限由系统配置,关键数据不足时发布最终报告并正常结束本轮,人工审核仅针对具体工单等业务动作。`,
|
||||
}),
|
||||
}).then(async (response) => {
|
||||
const reader = response.body?.getReader();
|
||||
|
||||
@@ -90,6 +90,11 @@ const payloadSchema = z.object({
|
||||
approval_mode: z.enum(["request", "always"]).optional().default("request"),
|
||||
capabilities: z.array(z.string().max(64)).max(20).optional().default([]),
|
||||
trigger_context: agentTriggerContextSchema.optional(),
|
||||
task_context: z.object({
|
||||
report_revision: z.number().int().positive().optional(),
|
||||
evidence_id: z.string().min(1).max(128).optional(),
|
||||
gap_id: z.string().min(1).max(128).optional(),
|
||||
}).strict().optional(),
|
||||
});
|
||||
|
||||
const toSessionUiStateContext = (sessionRecord: SessionRecord) => ({
|
||||
@@ -147,7 +152,8 @@ export const toCollaborationMessages = (messages: UIMessage[]) =>
|
||||
messages.flatMap((message) => {
|
||||
if (message.role !== "user" && message.role !== "assistant") return [];
|
||||
const content = readUiMessageText(message);
|
||||
return content ? [{ ...message, parts: [{ type: "text" as const, text: content }] } as UIMessage] : [];
|
||||
const reference = message.parts.filter((part) => part.type === "data-task_context");
|
||||
return content ? [{ ...message, parts: [{ type: "text" as const, text: content }, ...reference] } as UIMessage] : [];
|
||||
});
|
||||
|
||||
const toLegacyMessages = (messages: UIMessage[]) =>
|
||||
@@ -384,11 +390,18 @@ export const registerChatStreamRoute = (
|
||||
boundOperationalSessionId = binding.sessionId;
|
||||
const resolvedTaskContext = activeSessionRecord.taskId
|
||||
&& (sessionPurpose === "task_collaboration" || sessionPurpose === "task_execution")
|
||||
? await operationalTaskClient.getAgentContext(binding.sessionId, activeSessionRecord.taskId)
|
||||
? await operationalTaskClient.getAgentContext(binding.sessionId, activeSessionRecord.taskId,
|
||||
sessionPurpose === "task_collaboration" ? parsed.data.task_context?.report_revision : undefined)
|
||||
: null;
|
||||
const taskContext = sessionPurpose === "task_collaboration"
|
||||
? resolvedTaskContext
|
||||
: null;
|
||||
if (taskContext) {
|
||||
const report = taskContext.selected_report ?? taskContext.task.latest_report;
|
||||
const reference = z.object({ revision: z.number().int().positive() }).passthrough().safeParse(report);
|
||||
setRuntimeSessionContext({ ...getRuntimeSessionContext(binding.sessionId)!,
|
||||
reportRevision: reference.success ? reference.data.revision : undefined });
|
||||
}
|
||||
const hasRuntimeConversation = hadExistingRuntimeSession
|
||||
? await runtimeHasConversation(runtime, binding.sessionId)
|
||||
: false;
|
||||
@@ -882,10 +895,26 @@ export const registerChatStreamRoute = (
|
||||
taskHeartbeat?.unref();
|
||||
|
||||
try {
|
||||
if (taskContext) {
|
||||
const raw = taskContext.selected_report ?? taskContext.task.latest_report;
|
||||
const reportRef = z.object({ revision: z.number().int().positive(), execution_generation: z.number().int().positive().nullish() }).passthrough().safeParse(raw);
|
||||
const generation = taskContext.task.execution_generation;
|
||||
const reference = {
|
||||
task_id: activeSessionRecord.taskId!,
|
||||
execution_generation: reportRef.success ? reportRef.data.execution_generation ?? null
|
||||
: typeof generation === "number" && generation > 0 ? generation : null,
|
||||
report_revision: reportRef.success ? reportRef.data.revision : null,
|
||||
};
|
||||
const part = { type: "data-task_context" as const, data: reference };
|
||||
assistantParts.push(part);
|
||||
writeUiChunk(part);
|
||||
syncLatestUiMessages();
|
||||
}
|
||||
const preparedMessage = taskContext
|
||||
? [
|
||||
"你正在与用户协作理解一个工况任务。只根据下面由后端授权返回的任务、计划、报告和证据快照解释判断;不要展示后台执行会话、工具轨迹或内部推理。若资料不足,明确说明缺口。用户要求变更任务时使用结构化工具写回。",
|
||||
"你正在与用户协作理解一个工况任务。只根据下面由后端授权返回的任务、报告和证据解释判断;selected_report 存在时用户正在阅读该轮次与修订号,优先据此回答并明确引用。不要展示后台执行会话、工具轨迹或内部推理。普通提问不改变任务,只有用户明确补充的事实可用结构化工具记录并重新分析;假设和查询要求不能当作现场事实。queued 表示等待领取,不能声称已经开始分析。",
|
||||
`任务快照:${JSON.stringify(taskContext)}`,
|
||||
`当前讨论对象:${JSON.stringify(parsed.data.task_context ?? {})}`,
|
||||
`用户问题:${promptText}`,
|
||||
].join("\n\n")
|
||||
: await buildPromptWithLearningContext(
|
||||
|
||||
Reference in New Issue
Block a user