feat(workbench): refine dynamic task collaboration
This commit is contained in:
@@ -10,7 +10,8 @@ const taskSourceSchema = z.object({
|
||||
kind: z.enum(["schedule", "external_system", "operator", "agent"]),
|
||||
external_id: z.string().min(1).nullable(),
|
||||
external_revision: z.number().int().positive().nullable(),
|
||||
event_kind: z.string().min(1).nullable()
|
||||
event_kind: z.string().min(1).nullable(),
|
||||
deleted_at: workbenchDateTimeSchema.nullish()
|
||||
}).strict();
|
||||
const taskTriggerSchema = z.object({
|
||||
kind: z.enum(["schedule", "external_sync", "event", "manual"]),
|
||||
@@ -78,14 +79,19 @@ const planNodeSchema = z.object({
|
||||
status: z.enum(["pending", "waiting", "running", "completed", "failed", "skipped", "cancelled"]),
|
||||
detail: z.string().min(1),
|
||||
evidence_refs: z.array(z.string().min(1)),
|
||||
action_refs: z.array(z.string().uuid())
|
||||
action_refs: z.array(z.string().uuid()),
|
||||
kind: z.enum(["activity", "decision", "parallel_split", "parallel_join", "gate"]).nullish(),
|
||||
selected_edge_id: z.string().min(1).nullish(),
|
||||
gate_ref: z.string().uuid().nullish(),
|
||||
revisits_node_id: z.string().min(1).nullish()
|
||||
}).strict();
|
||||
const planInputSchema = z.object({
|
||||
schema: z.literal("execution-plan@1"),
|
||||
schema: z.enum(["execution-plan@1", "execution-plan@2"]),
|
||||
title: z.string().min(1),
|
||||
reason: z.string().min(1),
|
||||
nodes: z.array(planNodeSchema).min(1).max(100),
|
||||
edges: z.array(z.object({
|
||||
id: z.string().min(1).nullish(),
|
||||
from: z.string().min(1),
|
||||
to: z.string().min(1),
|
||||
condition: z.string().min(1).nullable()
|
||||
@@ -139,6 +145,8 @@ const actionSchema = z.object({
|
||||
execution_request_id: z.string().uuid().nullable(),
|
||||
proposed_by: z.string().min(1),
|
||||
proposed_at: workbenchDateTimeSchema,
|
||||
edited_by: z.string().min(1).nullish(),
|
||||
edited_at: workbenchDateTimeSchema.nullish(),
|
||||
decided_by: z.string().min(1).nullable(),
|
||||
decided_at: workbenchDateTimeSchema.nullable(),
|
||||
decision_comment: z.string().min(1).nullable(),
|
||||
@@ -147,6 +155,21 @@ const actionSchema = z.object({
|
||||
receipt: actionReceiptSchema.nullable(),
|
||||
execution_detail: z.string().min(1).nullable()
|
||||
}).strict();
|
||||
const accessRequestSchema = z.object({
|
||||
access_request_id: z.string().uuid(),
|
||||
task_id: z.string().uuid(),
|
||||
node_id: z.string().min(1),
|
||||
scopes: z.array(z.string().min(1)),
|
||||
reason: z.string().min(1),
|
||||
status: z.enum(["pending", "approved", "rejected"]),
|
||||
approved_scopes: z.array(z.string().min(1)),
|
||||
version: z.number().int().positive(),
|
||||
requested_by: z.string().min(1),
|
||||
requested_at: workbenchDateTimeSchema,
|
||||
decided_by: z.string().min(1).nullable(),
|
||||
decided_at: workbenchDateTimeSchema.nullable(),
|
||||
comment: z.string().min(1).nullable()
|
||||
}).strict();
|
||||
const taskPermissionsSchema = z.object({
|
||||
can_publish_artifacts: z.boolean(),
|
||||
can_propose_actions: z.boolean(),
|
||||
@@ -154,7 +177,8 @@ const taskPermissionsSchema = z.object({
|
||||
can_decide_work_orders: z.boolean(),
|
||||
can_execute_work_orders: z.boolean(),
|
||||
can_decide_commands: z.boolean(),
|
||||
can_execute_commands: z.boolean()
|
||||
can_execute_commands: z.boolean(),
|
||||
can_decide_access: z.boolean().default(false)
|
||||
}).strict();
|
||||
const externalWorkOrderActivitySchema = z.object({
|
||||
sequence: z.number().int().positive(),
|
||||
@@ -192,6 +216,7 @@ const operationalTaskSchema = taskSummarySchema.extend({
|
||||
latest_report: reportRevisionSchema.nullable(),
|
||||
evidence: z.array(evidenceSchema),
|
||||
actions: z.array(actionSchema),
|
||||
access_requests: z.array(accessRequestSchema).default([]),
|
||||
permissions: taskPermissionsSchema,
|
||||
work_order_snapshot: externalWorkOrderSnapshotSchema.nullable().default(null)
|
||||
}).strict();
|
||||
@@ -212,6 +237,11 @@ const notificationSchema = z.object({
|
||||
]),
|
||||
title: z.string().min(1),
|
||||
description: z.string().min(1),
|
||||
lifecycle_status: z.enum(["active", "resolved"]).default("active"),
|
||||
subject_type: z.enum(["task", "run", "access_request", "action"]).default("task"),
|
||||
subject_id: z.string().uuid().nullable().default(null),
|
||||
resolved_at: workbenchDateTimeSchema.nullable().default(null),
|
||||
resolution_reason: z.string().min(1).nullable().default(null),
|
||||
status: z.enum(["unread", "read"]),
|
||||
version: z.number().int().positive(),
|
||||
required_permission: z.string().min(1).nullable(),
|
||||
@@ -252,6 +282,7 @@ export type OperationalTaskSummary = z.infer<typeof taskSummarySchema>;
|
||||
export type OperationalTask = z.infer<typeof operationalTaskSchema>;
|
||||
export type OperationalTaskPlan = z.infer<typeof planInputSchema>;
|
||||
export type OperationalTaskAction = z.infer<typeof actionSchema>;
|
||||
export type OperationalTaskAccessRequest = z.infer<typeof accessRequestSchema>;
|
||||
export type OperationalTaskEvidence = z.infer<typeof evidenceSchema>;
|
||||
export type OperationalTaskNotification = z.infer<typeof notificationSchema>;
|
||||
export type OperationalTaskSchedule = z.infer<typeof scheduleSchema>;
|
||||
@@ -336,6 +367,34 @@ export async function executeOperationalTaskAction(taskId: string, actionId: str
|
||||
));
|
||||
}
|
||||
|
||||
export async function updateOperationalWorkOrderDraft(taskId: string, actionId: string, input: {
|
||||
request_id: string; expected_version: number; payload: Record<string, unknown>;
|
||||
}, getAccessToken?: AccessTokenProvider) {
|
||||
return actionSchema.parse(await operationalTaskRequest(
|
||||
`/operational-tasks/${encodeURIComponent(taskId)}/actions/${encodeURIComponent(actionId)}/draft`,
|
||||
getAccessToken, { method: "PATCH", body: JSON.stringify(input) }
|
||||
));
|
||||
}
|
||||
|
||||
export async function confirmOperationalWorkOrderDispatch(taskId: string, actionId: string, input: {
|
||||
request_id: string; expected_version: number;
|
||||
}, getAccessToken?: AccessTokenProvider) {
|
||||
return actionSchema.parse(await operationalTaskRequest(
|
||||
`/operational-tasks/${encodeURIComponent(taskId)}/actions/${encodeURIComponent(actionId)}/confirm-dispatch`,
|
||||
getAccessToken, { method: "POST", body: JSON.stringify(input) }
|
||||
));
|
||||
}
|
||||
|
||||
export async function decideOperationalTaskAccess(taskId: string, accessRequestId: string, input: {
|
||||
request_id: string; expected_version: number; decision: "approved" | "rejected";
|
||||
approved_scopes: string[]; comment?: string;
|
||||
}, getAccessToken?: AccessTokenProvider) {
|
||||
return accessRequestSchema.parse(await operationalTaskRequest(
|
||||
`/operational-tasks/${encodeURIComponent(taskId)}/access-requests/${encodeURIComponent(accessRequestId)}/decision`,
|
||||
getAccessToken, { method: "POST", body: JSON.stringify(input) }
|
||||
));
|
||||
}
|
||||
|
||||
export async function fetchOperationalTaskNotifications(getAccessToken?: AccessTokenProvider, signal?: AbortSignal) {
|
||||
return notificationPageSchema.parse(await operationalTaskRequest(
|
||||
"/operational-task-notifications?unread_only=true&limit=100&offset=0",
|
||||
|
||||
Reference in New Issue
Block a user