feat(server): integrate MCP queries and investigation messaging
Add project-bound OAuth MCP queries and controlled analysis with scoped evidence, limits, timeouts and a nearby-model spatial query using EPSG:4326 inputs. Default nearby searches to 200 meters and five results. Integrate investigation messaging/presentation, health/readiness and typed history; remove duplicate web search and fix online simulation and compressed baseline writes. Include project migrations 023-025; keep local credentials and demo seeding excluded. Validation: 319 focused pytest checks; real PostGIS temporary-table regression; read-only Jinqian bridge radius comparison; cross-language MCP discovery/calls.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
-- Latest investigation reading snapshots and controlled browser presentation events.
|
||||
BEGIN;
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF current_database() <> 'tjwater_v2' THEN
|
||||
RAISE EXCEPTION 'Investigation progress migration is restricted to tjwater_v2';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workbench.operational_task_progress (
|
||||
project_id uuid NOT NULL,
|
||||
task_id uuid NOT NULL,
|
||||
run_id uuid NOT NULL,
|
||||
revision bigint NOT NULL CHECK (revision >= 1),
|
||||
document jsonb NOT NULL,
|
||||
published_at timestamptz NOT NULL,
|
||||
PRIMARY KEY (project_id,task_id,run_id),
|
||||
FOREIGN KEY (project_id,task_id)
|
||||
REFERENCES workbench.operational_tasks(project_id,task_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (project_id,run_id)
|
||||
REFERENCES workbench.operational_task_runs(project_id,run_id) ON DELETE CASCADE,
|
||||
CHECK ((jsonb_typeof(document)='object'
|
||||
AND document->>'run_id'=run_id::text
|
||||
AND (document->>'revision')::bigint=revision) IS TRUE)
|
||||
);
|
||||
|
||||
ALTER TABLE workbench.domain_event_log
|
||||
DROP CONSTRAINT IF EXISTS domain_event_log_topic_check;
|
||||
ALTER TABLE workbench.domain_event_log ADD CONSTRAINT domain_event_log_topic_check
|
||||
CHECK (topic IN (
|
||||
'operational.task.changed','operational.run.queued','operational.run.changed',
|
||||
'operational.report.published','operational.progress.changed',
|
||||
'operational.presentation.requested','operational.action.changed',
|
||||
'operational.notification.changed','workbench.alert.changed',
|
||||
'workbench.work_order.changed','analysis.run.changed'
|
||||
));
|
||||
|
||||
COMMENT ON TABLE workbench.operational_task_progress IS
|
||||
'One latest complete reading snapshot per investigation run; never an execution scheduler.';
|
||||
COMMIT;
|
||||
@@ -0,0 +1,42 @@
|
||||
-- Private messages are deliberately excluded from the project event log.
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workbench.agent_messages (
|
||||
project_id uuid NOT NULL,
|
||||
message_id uuid NOT NULL,
|
||||
request_id uuid NOT NULL,
|
||||
task_id uuid NOT NULL,
|
||||
run_id uuid NOT NULL,
|
||||
source_session_id text NOT NULL CHECK (length(source_session_id)>0),
|
||||
source_owner_id uuid NOT NULL,
|
||||
conversation_owner_id uuid NOT NULL,
|
||||
target_session_id text,
|
||||
direction text NOT NULL CHECK (direction IN ('to_task','to_chat')),
|
||||
in_reply_to uuid,
|
||||
text text NOT NULL CHECK (length(text) BETWEEN 1 AND 12000 AND text ~ '\S'),
|
||||
status text NOT NULL CHECK (status IN ('pending','enqueued','delivered','failed')),
|
||||
native_message_id text NOT NULL,
|
||||
failure_detail text,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL,
|
||||
delivered_at timestamptz,
|
||||
PRIMARY KEY (project_id,message_id),
|
||||
UNIQUE (project_id,source_owner_id,source_session_id,request_id),
|
||||
FOREIGN KEY (project_id,task_id)
|
||||
REFERENCES workbench.operational_tasks(project_id,task_id),
|
||||
FOREIGN KEY (project_id,run_id)
|
||||
REFERENCES workbench.operational_task_runs(project_id,run_id),
|
||||
FOREIGN KEY (project_id,in_reply_to)
|
||||
REFERENCES workbench.agent_messages(project_id,message_id),
|
||||
CHECK ((direction='to_task')
|
||||
OR (direction='to_chat' AND in_reply_to IS NOT NULL AND target_session_id IS NOT NULL))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS agent_messages_pending_idx
|
||||
ON workbench.agent_messages(project_id,created_at,message_id)
|
||||
WHERE status IN ('pending','enqueued');
|
||||
CREATE INDEX IF NOT EXISTS agent_messages_owner_session_idx
|
||||
ON workbench.agent_messages(project_id,conversation_owner_id,created_at);
|
||||
CREATE INDEX IF NOT EXISTS agent_messages_run_idx
|
||||
ON workbench.agent_messages(project_id,run_id,status);
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,27 @@
|
||||
-- Additive MCP storage. Apply through the existing project database workflow.
|
||||
-- No access token, refresh token or OAuth client secret is stored here.
|
||||
BEGIN;
|
||||
CREATE TABLE IF NOT EXISTS workbench.mcp_query_contexts (
|
||||
context_handle text PRIMARY KEY,
|
||||
project_id uuid NOT NULL,
|
||||
subject text NOT NULL,
|
||||
client_id text NOT NULL,
|
||||
document jsonb NOT NULL,
|
||||
expires_at timestamptz NOT NULL,
|
||||
revoked_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS mcp_query_context_owner
|
||||
ON workbench.mcp_query_contexts (project_id,subject,client_id);
|
||||
CREATE INDEX IF NOT EXISTS mcp_query_context_expiry
|
||||
ON workbench.mcp_query_contexts (project_id,expires_at);
|
||||
CREATE TABLE IF NOT EXISTS workbench.mcp_query_receipts (
|
||||
project_id uuid NOT NULL,
|
||||
scope_key text NOT NULL,
|
||||
call_id text NOT NULL,
|
||||
parameters jsonb NOT NULL,
|
||||
result jsonb NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (project_id,scope_key,call_id)
|
||||
);
|
||||
COMMIT;
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: appointment-follow-up
|
||||
description: 调查关联预约任务的执行状态与反馈,核对审批、派发和现场结果,避免把预约任务当成新的爆管或投诉事件。
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# 预约任务跟进
|
||||
|
||||
预约工单承载已安排的人工工作。先读取原任务、已审批动作、预约时间、派发状态和现场反馈;需要时追溯关联的投诉或爆管事件。预约时间、工单派发时间、现场完成时间和事件发生时间分别说明。
|
||||
|
||||
核对预约工作的内容、执行条件和实际回执。只有现场反馈与证据支持时,才能认定采样、通知、抢修、冲洗或复测完成;工单创建或派发成功仅代表流程状态变化。对尚未完成的工作,报告责任事项、已有进展、缺少的反馈和下一步依赖。
|
||||
|
||||
预约工单不自动触发隔离停水或污染水排放,也不生成同类型的投诉、爆管事件。确有新增处置需要且已有证据支持时,保存阶段报告,再提议具体的关联预约工单(work_order_type=general),供人工审批;先核查已有有效草稿,避免在跟进过程中递归建单。
|
||||
|
||||
如发现新的爆管或水质风险,明确记录有依据的发现及待核验项,不擅自更改当前任务类型。审批、现场操作、业务重新排队和恢复供水均遵守现有 Server 流程。正式报告保留所用流程名称和版本,便于追溯。
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: burst-report
|
||||
description: 调查供水爆管上报,形成隔离停水、用户通知、抢修和恢复供水的处置方案及待审批动作。
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# 爆管上报处置
|
||||
|
||||
依据上报位置、时间、现场描述、相关管段台账和同窗压力流量证据,区分上报事实、爆管候选、已确认故障与演练假设。完成初步风险判断不要求抢修、复测和回访已经发生;这些属于后续执行反馈。演练数据可支持明确标注的演练判断,不能证明生产故障。
|
||||
|
||||
## 调查与处置路线
|
||||
|
||||
1. 核对上报对象与时间窗,查询相关管段、周边监测和既有处置反馈。先确定实际覆盖范围;目录首屏或查询错误不能证明全网没有异常。具备输入时使用爆管侦测或定位分析,候选结果仍需现场核验。
|
||||
2. 形成隔离停水方案。已确认目标管段时,按需分析隔离阀门、关阀影响、失供范围和供水保障。资产映射、阀门状态或影响范围不清时,明确待现场核验条件;不得编造阀门编号或直接生成无目标的设备命令。
|
||||
3. 安排用户通知和供水保障。草稿写明已知影响区域、拟停水时段或“待确认”、通知内容、通知渠道及责任岗位;关阀前通知与紧急处置后的补通知取决于现场紧迫性和获批方案。未知用户数量不填虚构值。通知草稿或内部调查消息均不能说成用户已收到通知。
|
||||
4. 安排现场定位、止水与抢修。说明施工位置、隔离前置条件、抢修目标和需要回传的现场事实。存在管内污染侵入风险时,再安排适用的清洗、消毒或冲洗评估,不能把每次爆管都判断为污染事件。
|
||||
5. 恢复供水前核验修复、压力、漏水复查及适用的水质复测结果,按获批方案恢复并通知用户;缺少现场反馈时保留“待执行/待核验”,不能宣称恢复完成。
|
||||
|
||||
## 报告与动作草稿
|
||||
|
||||
报告说明当前判断、证据覆盖、隔离影响、通知安排、抢修及恢复条件。能够形成有边界的初步判断时,不因后续维修或复测尚未完成而把整个调查判为关键数据不足。确实缺少支撑当前判断的关键证据时,遵守 insufficient_data 契约,不强造结论或动作。
|
||||
|
||||
在已有证据足以支持具体处置建议时,先保存阶段报告,再通过现有动作提议入口保存待人工审批的具体草稿。现场核验、停水通知、抢修等人工执行事项使用关联预约工单(work_order_type=general);原爆管上报事件保持独立。草稿含位置、工作内容、先后依赖、执行前核验条件和回执要求,避免为每个图节点机械建单。没有实际客户通知工具时,将通知列为待执行的人工工单步骤。
|
||||
|
||||
有真实且可控制的设备目标、明确命令及充分依据时,才提议设备命令。审批和执行由 Server 控制,调查不直接关闭阀门或发送用户通知。复用已存在的有效草稿,结合实际回执继续调查,不重复提议同一动作。正式报告保留所用流程名称和版本,便于追溯。
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: water-quality-complaint
|
||||
description: 调查供水水质投诉,按证据和风险提出采样、隔离、用户通知、污染水处置及复测恢复方案。
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# 水质投诉处置
|
||||
|
||||
区分用户感官投诉、监测异常、已确认的水质问题与污染源假设。单个投诉不能直接证明供水管网污染;上游监测正常也不能排除末梢或二次供水问题。不预设异常必然来自二次供水,不把模拟扩散结果当成污染源反演。
|
||||
|
||||
## 调查与处置路线
|
||||
|
||||
1. 核对投诉时间、位置、异常描述与同类投诉,查询供水路径、相关水质和压力监测、适用的历史记录及现场采样反馈。分别说明实际覆盖的上游、末梢和二次供水范围,不混用模型基线与实测。
|
||||
2. 评估是否需要隔离停水及饮用水风险告知。已确认或有充分证据支持局部供水风险时,提出与风险相称的隔离范围和保障措施,核对阀门与影响区域。尚不能确定风险时,先提出有依据的现场核验或采样安排,不因一条投诉直接建议全网停水,也不承诺水可安全饮用。
|
||||
3. 将用户通知纳入处置方案:明确已知影响范围、需人工确认的用水提示、通知渠道、责任岗位和更新条件。没有实际发送工具时形成待审批的人工通知步骤,不把调查消息当成客户通知。
|
||||
4. 对已支持的污染水风险,安排排查来源、控制污染进入并评估受影响管段的冲洗或排放。仅在来源参数、目标管段或冲洗节点等必需输入已知时使用扩散或冲洗分析;参数不足不虚构源浓度、排放量或节点。具体排水位置、承接条件及现场操作要求需核验后审批执行,不默认污染水可任意排放。
|
||||
5. 清洗或冲洗后取得适用采样和复测反馈,再评估恢复供水与用户回访。现场处置、复测和恢复是下游执行步骤,其尚未发生不能单独作为拒绝初步风险分析的理由。
|
||||
|
||||
## 报告与动作草稿
|
||||
|
||||
报告列明当前风险判断、证据覆盖、隔离与通知条件、污染水处置路线和复测恢复条件。演练输入只支持标注为演练的判断。真正缺少支撑当前判断的关键证据时,遵守 insufficient_data 契约,不用通用处置模板强造已确认污染结论。
|
||||
|
||||
已能形成有边界的处置建议时,保存阶段报告后,通过现有动作提议入口生成待人工审批的关联预约工单(work_order_type=general)。保留原投诉事件,草稿写明实际位置、采样或处置内容、责任要求、执行依赖、现场待核验条件和回执要求;可将通知、采样、冲洗和复测组织成合理的人工执行事项,不机械逐节点建单。
|
||||
|
||||
设备命令只针对真实且可控制的目标,审批与执行由 Server 控制。草稿保存或工单派发不等于采样、通知、冲洗、复测完成。核对已有草稿和现场反馈后再继续,避免重复提议。正式报告保留所用流程名称和版本,便于追溯。
|
||||
Reference in New Issue
Block a user