feat(tasks): enforce dynamic execution plans
This commit is contained in:
Vendored
+649
-2
@@ -2327,6 +2327,40 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/access-requests": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Request Operational Task Access */
|
||||
post: operations["post_operational_tasks_task_id_access_requests"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/access-requests/{access_request_id}/decision": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Decide Operational Task Access */
|
||||
post: operations["post_operational_tasks_task_id_access_requests_access_request_id_decision"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/actions": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2344,6 +2378,23 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/actions/{action_id}/confirm-dispatch": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Confirm Operational Work Order Dispatch */
|
||||
post: operations["post_operational_tasks_task_id_actions_action_id_confirm_dispatch"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/actions/{action_id}/decision": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2361,6 +2412,23 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/actions/{action_id}/draft": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
/** Update Operational Work Order Draft */
|
||||
patch: operations["patch_operational_tasks_task_id_actions_action_id_draft"];
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/actions/{action_id}/execute": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2616,6 +2684,23 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/operational-tasks/{task_id}/withdraw-external-source": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Withdraw Operational Task External Source */
|
||||
post: operations["post_operational_tasks_task_id_withdraw_external_source"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/patterns": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -5983,6 +6068,8 @@ export interface components {
|
||||
condition?: string | null;
|
||||
/** From */
|
||||
from: string;
|
||||
/** Id */
|
||||
id?: string | null;
|
||||
/** To */
|
||||
to: string;
|
||||
};
|
||||
@@ -5996,9 +6083,9 @@ export interface components {
|
||||
reason: string;
|
||||
/**
|
||||
* Schema
|
||||
* @constant
|
||||
* @enum {string}
|
||||
*/
|
||||
schema: "execution-plan@1";
|
||||
schema: "execution-plan@1" | "execution-plan@2";
|
||||
/** Title */
|
||||
title: string;
|
||||
};
|
||||
@@ -6010,13 +6097,21 @@ export interface components {
|
||||
detail: string;
|
||||
/** Evidence Refs */
|
||||
evidence_refs?: string[];
|
||||
/** Gate Ref */
|
||||
gate_ref?: string | null;
|
||||
/** Id */
|
||||
id: string;
|
||||
/** Kind */
|
||||
kind?: ("activity" | "decision" | "parallel_split" | "parallel_join" | "gate") | null;
|
||||
/**
|
||||
* Owner
|
||||
* @enum {string}
|
||||
*/
|
||||
owner: "agent" | "human";
|
||||
/** Revisits Node Id */
|
||||
revisits_node_id?: string | null;
|
||||
/** Selected Edge Id */
|
||||
selected_edge_id?: string | null;
|
||||
/**
|
||||
* Status
|
||||
* @enum {string}
|
||||
@@ -6103,6 +6198,16 @@ export interface components {
|
||||
source_revision: number;
|
||||
task: components["schemas"]["OperationalTaskDetail"];
|
||||
};
|
||||
/** ExternalSourceWithdrawalCommand */
|
||||
ExternalSourceWithdrawalCommand: {
|
||||
/**
|
||||
* Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
request_id: string;
|
||||
/** Source Event Id */
|
||||
source_event_id: string;
|
||||
};
|
||||
/** ExternalWorkOrderSnapshot */
|
||||
ExternalWorkOrderSnapshot: {
|
||||
/** Activity */
|
||||
@@ -6230,6 +6335,10 @@ export interface components {
|
||||
decided_by?: string | null;
|
||||
/** Decision Comment */
|
||||
decision_comment?: string | null;
|
||||
/** Edited At */
|
||||
edited_at?: string | null;
|
||||
/** Edited By */
|
||||
edited_by?: string | null;
|
||||
/** Evidence Refs */
|
||||
evidence_refs: string[];
|
||||
/** Executed At */
|
||||
@@ -6552,6 +6661,8 @@ export interface components {
|
||||
};
|
||||
/** OperationalTaskDetail */
|
||||
OperationalTaskDetail: {
|
||||
/** Access Requests */
|
||||
access_requests?: components["schemas"]["TaskAccessRequest"][];
|
||||
/** Actions */
|
||||
actions: components["schemas"]["HumanApprovalAction"][];
|
||||
active_run?: components["schemas"]["OperationalTaskRun"] | null;
|
||||
@@ -6644,6 +6755,12 @@ export interface components {
|
||||
* @enum {string}
|
||||
*/
|
||||
kind: "task_created" | "action_pending" | "report_updated" | "task_completed" | "task_failed" | "run_delivery_degraded" | "access_approval_pending" | "action_approval_pending" | "human_input_required" | "external_coordination_failed";
|
||||
/**
|
||||
* Lifecycle Status
|
||||
* @default active
|
||||
* @enum {string}
|
||||
*/
|
||||
lifecycle_status: "active" | "resolved";
|
||||
/**
|
||||
* Notification Id
|
||||
* Format: uuid
|
||||
@@ -6655,11 +6772,23 @@ export interface components {
|
||||
read_by?: string | null;
|
||||
/** Required Permission */
|
||||
required_permission?: string | null;
|
||||
/** Resolution Reason */
|
||||
resolution_reason?: string | null;
|
||||
/** Resolved At */
|
||||
resolved_at?: string | null;
|
||||
/**
|
||||
* Status
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "unread" | "read";
|
||||
/** Subject Id */
|
||||
subject_id?: string | null;
|
||||
/**
|
||||
* Subject Type
|
||||
* @default task
|
||||
* @enum {string}
|
||||
*/
|
||||
subject_type: "task" | "run" | "access_request" | "action";
|
||||
/**
|
||||
* Task Id
|
||||
* Format: uuid
|
||||
@@ -6694,6 +6823,11 @@ export interface components {
|
||||
};
|
||||
/** OperationalTaskPermissions */
|
||||
OperationalTaskPermissions: {
|
||||
/**
|
||||
* Can Decide Access
|
||||
* @default false
|
||||
*/
|
||||
can_decide_access: boolean;
|
||||
/** Can Decide Commands */
|
||||
can_decide_commands: boolean;
|
||||
/** Can Decide Work Orders */
|
||||
@@ -7536,6 +7670,82 @@ export interface components {
|
||||
/** Source Fid */
|
||||
source_fid: number;
|
||||
};
|
||||
/** TaskAccessRequest */
|
||||
TaskAccessRequest: {
|
||||
/**
|
||||
* Access Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
access_request_id: string;
|
||||
/** Approved Scopes */
|
||||
approved_scopes: ("workbench_runtime" | "scada_devices" | "scada_readings" | "peripheral_points" | "peripheral_work_orders" | "peripheral_observations" | "peripheral_test_data")[];
|
||||
/** Comment */
|
||||
comment?: string | null;
|
||||
/** Decided At */
|
||||
decided_at?: string | null;
|
||||
/** Decided By */
|
||||
decided_by?: string | null;
|
||||
/** Node Id */
|
||||
node_id: string;
|
||||
/** Reason */
|
||||
reason: string;
|
||||
/**
|
||||
* Requested At
|
||||
* Format: date-time
|
||||
*/
|
||||
requested_at: string;
|
||||
/** Requested By */
|
||||
requested_by: string;
|
||||
/** Scopes */
|
||||
scopes: ("workbench_runtime" | "scada_devices" | "scada_readings" | "peripheral_points" | "peripheral_work_orders" | "peripheral_observations" | "peripheral_test_data")[];
|
||||
/**
|
||||
* Status
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "pending" | "approved" | "rejected";
|
||||
/**
|
||||
* Task Id
|
||||
* Format: uuid
|
||||
*/
|
||||
task_id: string;
|
||||
/** Version */
|
||||
version: number;
|
||||
};
|
||||
/** TaskAccessRequestCreate */
|
||||
TaskAccessRequestCreate: {
|
||||
/** Node Id */
|
||||
node_id: string;
|
||||
/** Reason */
|
||||
reason: string;
|
||||
/**
|
||||
* Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
request_id: string;
|
||||
/** Scopes */
|
||||
scopes: ("workbench_runtime" | "scada_devices" | "scada_readings" | "peripheral_points" | "peripheral_work_orders" | "peripheral_observations" | "peripheral_test_data")[];
|
||||
/** Source Session Id */
|
||||
source_session_id: string;
|
||||
};
|
||||
/** TaskAccessRequestDecision */
|
||||
TaskAccessRequestDecision: {
|
||||
/** Approved Scopes */
|
||||
approved_scopes?: ("workbench_runtime" | "scada_devices" | "scada_readings" | "peripheral_points" | "peripheral_work_orders" | "peripheral_observations" | "peripheral_test_data")[];
|
||||
/** Comment */
|
||||
comment?: string | null;
|
||||
/**
|
||||
* Decision
|
||||
* @enum {string}
|
||||
*/
|
||||
decision: "approved" | "rejected";
|
||||
/** Expected Version */
|
||||
expected_version: number;
|
||||
/**
|
||||
* Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
request_id: string;
|
||||
};
|
||||
/** TaskAlertCommand */
|
||||
TaskAlertCommand: {
|
||||
/** Alert Id */
|
||||
@@ -7650,6 +7860,8 @@ export interface components {
|
||||
};
|
||||
/** TaskSource */
|
||||
TaskSource: {
|
||||
/** Deleted At */
|
||||
deleted_at?: string | null;
|
||||
/** Event Kind */
|
||||
event_kind?: string | null;
|
||||
/** External Id */
|
||||
@@ -7742,6 +7954,27 @@ export interface components {
|
||||
/** Title */
|
||||
title: string;
|
||||
};
|
||||
/** WorkOrderConfirmDispatchCommand */
|
||||
WorkOrderConfirmDispatchCommand: {
|
||||
/** Expected Version */
|
||||
expected_version: number;
|
||||
/**
|
||||
* Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
request_id: string;
|
||||
};
|
||||
/** WorkOrderDraftUpdateCommand */
|
||||
WorkOrderDraftUpdateCommand: {
|
||||
/** Expected Version */
|
||||
expected_version: number;
|
||||
payload: components["schemas"]["CreateWorkOrderPayload"];
|
||||
/**
|
||||
* Request Id
|
||||
* Format: uuid
|
||||
*/
|
||||
request_id: string;
|
||||
};
|
||||
/** WorkbenchAlertSource */
|
||||
WorkbenchAlertSource: {
|
||||
/** Run Id */
|
||||
@@ -19772,6 +20005,171 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_access_requests: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
"X-Project-Id": string;
|
||||
};
|
||||
path: {
|
||||
task_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["TaskAccessRequestCreate"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["TaskAccessRequest"];
|
||||
};
|
||||
};
|
||||
/** @description Authentication required */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Insufficient permission */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Validation error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Dependency unavailable */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_access_requests_access_request_id_decision: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
"X-Project-Id": string;
|
||||
};
|
||||
path: {
|
||||
task_id: string;
|
||||
access_request_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["TaskAccessRequestDecision"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["TaskAccessRequest"];
|
||||
};
|
||||
};
|
||||
/** @description Authentication required */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Insufficient permission */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Validation error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Dependency unavailable */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_actions: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -19854,6 +20252,90 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_actions_action_id_confirm_dispatch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
Authorization?: string | null;
|
||||
"X-Project-Id": string;
|
||||
};
|
||||
path: {
|
||||
task_id: string;
|
||||
action_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["WorkOrderConfirmDispatchCommand"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HumanApprovalAction"];
|
||||
};
|
||||
};
|
||||
/** @description Authentication required */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Insufficient permission */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Validation error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Dependency unavailable */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_actions_action_id_decision: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -19937,6 +20419,89 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
patch_operational_tasks_task_id_actions_action_id_draft: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
"X-Project-Id": string;
|
||||
};
|
||||
path: {
|
||||
task_id: string;
|
||||
action_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["WorkOrderDraftUpdateCommand"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HumanApprovalAction"];
|
||||
};
|
||||
};
|
||||
/** @description Authentication required */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Insufficient permission */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Validation error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Dependency unavailable */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_actions_action_id_execute: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -21171,6 +21736,88 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
post_operational_tasks_task_id_withdraw_external_source: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
"X-Project-Id": string;
|
||||
};
|
||||
path: {
|
||||
task_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["ExternalSourceWithdrawalCommand"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["OperationalTaskDetail"];
|
||||
};
|
||||
};
|
||||
/** @description Authentication required */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Insufficient permission */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Resource conflict */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Validation error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
/** @description Dependency unavailable */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ProblemDetails"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
get_patterns: {
|
||||
parameters: {
|
||||
query?: {
|
||||
|
||||
@@ -151,6 +151,12 @@ export const humanTaskEvidenceCommandSchema = z.object({
|
||||
export type TaskEvidence = z.infer<typeof taskEvidenceSchema>;
|
||||
export type TaskReport = z.infer<typeof taskReportSchema>;
|
||||
export type OperationalTaskDataQuery = z.infer<typeof operationalTaskDataQuerySchema>;
|
||||
export const expressAccessRequestSchema = z.object({
|
||||
requestId: z.string().uuid(),
|
||||
nodeId: z.string().min(1),
|
||||
scopes: z.array(taskDataSourceSchema).min(1).max(7),
|
||||
reason: z.string().min(1),
|
||||
});
|
||||
export type HumanTaskEvidenceCommand = z.infer<typeof humanTaskEvidenceCommandSchema>;
|
||||
|
||||
export type OperationalTaskContext = Record<string, unknown>;
|
||||
@@ -354,6 +360,18 @@ export class OperationalTaskClient {
|
||||
return { evidence, snapshot };
|
||||
}
|
||||
|
||||
async requestDataAccess(runtimeSessionId: string, taskId: string, input: {
|
||||
requestId: string; sourceSessionId: string; nodeId: string; scopes: OperationalTaskDataQuery["source"][]; reason: string;
|
||||
}) {
|
||||
return this.request(runtimeSessionId, `/api/v1/operational-tasks/${encodeURIComponent(taskId)}/access-requests`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
request_id: input.requestId, source_session_id: input.sourceSessionId,
|
||||
node_id: input.nodeId, scopes: input.scopes, reason: input.reason,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
async proposeAction(runtimeSessionId: string, taskId: string, input: ProposedTaskAction) {
|
||||
const result = await this.request(runtimeSessionId, `/api/v1/operational-tasks/${encodeURIComponent(taskId)}/actions`, {
|
||||
method: "POST",
|
||||
@@ -475,7 +493,7 @@ const toServerPlan = (input: Record<string, unknown>) => {
|
||||
const nodes = Array.isArray(input.nodes) ? input.nodes : [];
|
||||
const edges = Array.isArray(input.edges) ? input.edges : [];
|
||||
return {
|
||||
schema: "execution-plan@1",
|
||||
schema: input.schema === "execution-plan@2" ? "execution-plan@2" : "execution-plan@1",
|
||||
title: input.title,
|
||||
reason: input.reason,
|
||||
nodes: nodes.map((value) => {
|
||||
@@ -488,6 +506,12 @@ const toServerPlan = (input: Record<string, unknown>) => {
|
||||
detail: node.detail,
|
||||
evidence_refs: Array.isArray(node.evidence) ? node.evidence : [],
|
||||
action_refs: Array.isArray(node.action_refs) ? node.action_refs : [],
|
||||
...(input.schema === "execution-plan@2" ? {
|
||||
kind: node.kind,
|
||||
selected_edge_id: node.selected_edge_id ?? null,
|
||||
gate_ref: node.gate_ref ?? null,
|
||||
revisits_node_id: node.revisits_node_id ?? null,
|
||||
} : {}),
|
||||
};
|
||||
}),
|
||||
edges: edges.map((value) => {
|
||||
@@ -496,6 +520,7 @@ const toServerPlan = (input: Record<string, unknown>) => {
|
||||
from: edge.from,
|
||||
to: edge.to,
|
||||
...(typeof edge.label === "string" && edge.label.trim() ? { condition: edge.label } : {}),
|
||||
...(input.schema === "execution-plan@2" ? { id: edge.id } : {}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -33,8 +33,8 @@ export const buildAgentTriggerPrompt = (trigger: AgentTriggerContext) => [
|
||||
event_id: trigger.trigger_id,
|
||||
})}</external_work_order>`,
|
||||
"这是合成演练数据,不得表述为生产事实。",
|
||||
"开始调查前调用 publish_execution_plan 发布本次调查的结构化计划,明确并行依赖和条件分支;执行前、取得结果后、遇到阻塞或修改计划时再次发布完整快照。保留节点 ID、已完成节点及证据,重试用新节点,不要按时间推算进度。",
|
||||
"根据这张工单的事实动态规划本次调查,不套用预设路线。开始调查前调用 publish_execution_plan 发布 execution-plan@2,明确路线选择、并行分叉与汇合、人工审核点;执行前、取得结果后、遇到阻塞或修改计划时再次发布完整快照。保留节点 ID、已完成节点及证据,重试用新节点,不要按时间推算进度。",
|
||||
"每个完成节点必须列明实际依据。预设证据标注为合成场景输入,不得声称执行过未调用的数据查询工具。现场采样、清洗、复测、回访等人工工作保持 waiting,写清等待内容,不得因回复结束标记完成。",
|
||||
"外围样板随事件提供的合成场景输入(不是 Agent 实时查询结果):上游三个模拟水质监测点的数据质量均为 valid,演示指标均在场景阈值内,且相邻片区没有同类投诉;投诉集中在演示小区,二次供水水箱最近一次清洗记录待核验。",
|
||||
"请按‘上游数据质量正常、上游水质未见异常 → 疑似二次供水环节问题(待现场核验)’形成阶段性判断,并给出处置、复测和回访建议。不得将疑似判断写成已确认事故。",
|
||||
"依据实际取得的证据判断可能原因,区分合成场景输入、已查询数据和待现场核验事项;给出处置、复测和回访建议。不得将疑似判断写成已确认事故。",
|
||||
].join("\n");
|
||||
|
||||
@@ -105,7 +105,7 @@ export const registerChatSessionRoutes = (
|
||||
body: JSON.stringify({
|
||||
session_id: record.sessionId,
|
||||
model,
|
||||
message: `执行工况任务${workflow ? `:${workflow}` : ""}。先读取后端任务上下文,再按任务类型更新计划、证据和报告。`,
|
||||
message: `执行工况任务${workflow ? `:${workflow}` : ""}。先读取后端任务上下文,依据当前工单或人工请求动态规划 execution-plan@2;按实际选择的路线更新计划、证据和报告,数据权限不足时先申请并等待审核。`,
|
||||
}),
|
||||
}).then(async (response) => {
|
||||
const reader = response.body?.getReader();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { z } from "zod";
|
||||
|
||||
const id = z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/);
|
||||
export const executionPlanSchema = z.object({
|
||||
schema: z.enum(["execution-plan@1", "execution-plan@2"]).default("execution-plan@1"),
|
||||
title: z.string().trim().min(1).max(120),
|
||||
reason: z.string().trim().min(1).max(1000),
|
||||
nodes: z.array(z.object({
|
||||
@@ -12,18 +13,27 @@ export const executionPlanSchema = z.object({
|
||||
detail: z.string().max(2000),
|
||||
evidence: z.array(z.string().min(1).max(1000)).max(12),
|
||||
action_refs: z.array(z.string().uuid()).max(12).default([]),
|
||||
kind: z.enum(["activity", "decision", "parallel_split", "parallel_join", "gate"]).optional(),
|
||||
selected_edge_id: id.nullable().optional(),
|
||||
gate_ref: z.string().uuid().nullable().optional(),
|
||||
revisits_node_id: id.nullable().optional(),
|
||||
})).min(1).max(40),
|
||||
edges: z.array(z.object({ from: id, to: id, label: z.string().max(120) })).max(80),
|
||||
edges: z.array(z.object({ id: id.optional(), from: id, to: id, label: z.string().max(120) })).max(80),
|
||||
}).superRefine((plan, context) => {
|
||||
const ids = new Set(plan.nodes.map((node) => node.id));
|
||||
if (ids.size !== plan.nodes.length) context.addIssue({ code: "custom", message: "Duplicate node ID" });
|
||||
const edges = new Set<string>();
|
||||
const edgeIds = new Set<string>();
|
||||
for (const edge of plan.edges) {
|
||||
const key = `${edge.from}:${edge.to}`;
|
||||
if (!ids.has(edge.from) || !ids.has(edge.to) || edge.from === edge.to || edges.has(key)) {
|
||||
context.addIssue({ code: "custom", message: "Invalid or duplicate dependency" });
|
||||
}
|
||||
edges.add(key);
|
||||
if (plan.schema === "execution-plan@2") {
|
||||
if (!edge.id || edgeIds.has(edge.id)) context.addIssue({ code: "custom", message: "V2 edges require unique IDs" });
|
||||
if (edge.id) edgeIds.add(edge.id);
|
||||
}
|
||||
}
|
||||
const visiting = new Set<string>();
|
||||
const visited = new Set<string>();
|
||||
@@ -37,6 +47,35 @@ export const executionPlanSchema = z.object({
|
||||
return false;
|
||||
};
|
||||
if (plan.nodes.some((node) => visit(node.id))) context.addIssue({ code: "custom", message: "Dependencies must be acyclic; use a new node for a retry" });
|
||||
if (plan.schema === "execution-plan@2") {
|
||||
if (plan.nodes.filter((node) => !plan.edges.some((edge) => edge.to === node.id)).length !== 1) {
|
||||
context.addIssue({ code: "custom", message: "V2 plan requires one start node" });
|
||||
}
|
||||
const nodeById = new Map(plan.nodes.map((node) => [node.id, node]));
|
||||
for (const node of plan.nodes) {
|
||||
const outgoing = plan.edges.filter((edge) => edge.from === node.id);
|
||||
const incoming = plan.edges.filter((edge) => edge.to === node.id);
|
||||
if (!node.kind) context.addIssue({ code: "custom", message: "V2 nodes require kind" });
|
||||
if (node.kind === "decision") {
|
||||
if (outgoing.length < 2 || outgoing.some((edge) => !edge.label.trim())) context.addIssue({ code: "custom", message: "Decision routes must be labeled" });
|
||||
if (node.selected_edge_id && !outgoing.some((edge) => edge.id === node.selected_edge_id)) context.addIssue({ code: "custom", message: "Selected route must leave its decision" });
|
||||
if (node.status === "completed" && !node.selected_edge_id) context.addIssue({ code: "custom", message: "Completed decision requires a selected route" });
|
||||
if (node.selected_edge_id) {
|
||||
for (const edge of outgoing) {
|
||||
const targetStatus = nodeById.get(edge.to)?.status;
|
||||
if (edge.id === node.selected_edge_id && ["skipped", "cancelled"].includes(targetStatus ?? "")) context.addIssue({ code: "custom", message: "Selected route cannot be skipped" });
|
||||
if (edge.id !== node.selected_edge_id && ["running", "completed", "waiting"].includes(targetStatus ?? "")) context.addIssue({ code: "custom", message: "Unchosen route cannot be active" });
|
||||
}
|
||||
}
|
||||
} else if (node.selected_edge_id) context.addIssue({ code: "custom", message: "Only decisions select routes" });
|
||||
if (node.kind !== "decision" && node.kind !== "parallel_split" && outgoing.length > 1) context.addIssue({ code: "custom", message: "Only decisions or parallel splits may branch" });
|
||||
if (node.kind === "parallel_split" && outgoing.length < 2) context.addIssue({ code: "custom", message: "Parallel split requires two routes" });
|
||||
if (node.kind === "parallel_join" && incoming.length < 2) context.addIssue({ code: "custom", message: "Parallel join requires two inputs" });
|
||||
if (node.kind === "gate" && !node.gate_ref) context.addIssue({ code: "custom", message: "Gate requires a persisted reference" });
|
||||
if (node.kind !== "gate" && node.gate_ref) context.addIssue({ code: "custom", message: "Only gates reference approvals" });
|
||||
if (node.revisits_node_id && !ids.has(node.revisits_node_id)) context.addIssue({ code: "custom", message: "Revisited node must exist" });
|
||||
}
|
||||
}
|
||||
for (const node of plan.nodes) {
|
||||
if (node.status === "running" || node.status === "completed") {
|
||||
const hasIncompletePredecessor = plan.edges
|
||||
@@ -50,11 +89,21 @@ export const executionPlanSchema = z.object({
|
||||
message: "Running or completed nodes require completed or skipped predecessors",
|
||||
});
|
||||
}
|
||||
if (node.status === "completed" && node.evidence.length === 0 && node.action_refs.length === 0) context.addIssue({ code: "custom", message: "Completed nodes require evidence or an approved action receipt" });
|
||||
if (node.status === "completed" && node.evidence.length === 0 && node.action_refs.length === 0
|
||||
&& !(plan.schema === "execution-plan@2" && ["parallel_split", "parallel_join", "gate"].includes(node.kind ?? ""))) {
|
||||
context.addIssue({ code: "custom", message: "Completed nodes require evidence or an approved action receipt" });
|
||||
}
|
||||
if ((node.status === "waiting" || node.status === "failed") && !node.detail.trim()) context.addIssue({ code: "custom", message: "Waiting or failed nodes require a reason" });
|
||||
}
|
||||
});
|
||||
|
||||
// Stored v1 plans remain readable, but every newly published task plan must
|
||||
// opt into the graph and approval-gate guarantees of v2.
|
||||
export const newExecutionPlanSchema = executionPlanSchema.refine(
|
||||
(plan) => plan.schema === "execution-plan@2",
|
||||
{ message: "New task execution plans must use execution-plan@2", path: ["schema"] },
|
||||
);
|
||||
|
||||
export const executionPlanNeedsTaskPublish = (input: unknown) =>
|
||||
!(input && typeof input === "object" && (input as Record<string, unknown>).server_published === true);
|
||||
|
||||
@@ -84,5 +133,5 @@ export function createExecutionPlanSnapshot(input: unknown, messages: unknown[],
|
||||
}
|
||||
}
|
||||
}
|
||||
return { ...plan, schema_version: "execution-plan@1", session_id: sessionId, revision: history.length + 1, updated_at: new Date().toISOString() };
|
||||
return { ...plan, schema_version: plan.schema, session_id: sessionId, revision: history.length + 1, updated_at: new Date().toISOString() };
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { getRuntimeSessionContext } from "./runtime/sessionContext.js";
|
||||
import {
|
||||
operationalTaskClient,
|
||||
operationalTaskDataQuerySchema,
|
||||
expressAccessRequestSchema,
|
||||
humanTaskEvidenceCommandSchema,
|
||||
proposedTaskActionSchema,
|
||||
taskArtifactBridgeSchema,
|
||||
@@ -153,6 +154,28 @@ app.post("/internal/operational-task/data-query", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/internal/operational-task/access-requests", async (req, res) => {
|
||||
const bridge = readOperationalTaskBridgeContext(req);
|
||||
if (!bridge || bridge.context.purpose !== "task_execution") {
|
||||
res.status(403).json({ message: "task execution context required" });
|
||||
return;
|
||||
}
|
||||
const parsed = expressAccessRequestSchema.safeParse(req.body?.request);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ message: "invalid access request" });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
res.json(await operationalTaskClient.requestDataAccess(bridge.runtimeSessionId, bridge.taskId, {
|
||||
...parsed.data, sourceSessionId: bridge.context.clientSessionId,
|
||||
}));
|
||||
} catch (error) {
|
||||
const status = error && typeof error === "object" && "status" in error && typeof error.status === "number"
|
||||
? error.status : 502;
|
||||
res.status(status).json({ message: error instanceof Error ? error.message : "access request failed" });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/internal/operational-task/actions", async (req, res) => {
|
||||
const bridge = readOperationalTaskBridgeContext(req);
|
||||
if (!bridge) {
|
||||
|
||||
Reference in New Issue
Block a user