feat: expand intelligent investigation workspace
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { investigationReportSchema, investigationDiagramSchema } from "./investigation-report";
|
||||
import { investigationPresentationCursorSchema } from "./investigation-presentation";
|
||||
import { investigationPresentationCursorSchema, investigationPresentationHistoryPageSchema, type InvestigationPresentationHistoryEvent } from "./investigation-presentation";
|
||||
import type { WorkbenchAccess } from "./request-context";
|
||||
import { env } from "@/shared/config/env";
|
||||
import { createWorkbenchHeaders, findOwnedWorkbenchProject, getServerError } from "./project-client";
|
||||
@@ -191,6 +191,7 @@ const taskPermissionsSchema = z.object({
|
||||
can_execute_work_orders: z.boolean(),
|
||||
can_decide_commands: z.boolean(),
|
||||
can_execute_commands: z.boolean(),
|
||||
can_answer_questions: z.boolean().optional(),
|
||||
can_decide_access: z.boolean().default(false)
|
||||
}).strict();
|
||||
const externalWorkOrderActivitySchema = z.object({
|
||||
@@ -221,9 +222,25 @@ const externalWorkOrderSnapshotSchema = z.preprocess((value) => {
|
||||
scenario_code: z.string().min(1).nullable(),
|
||||
feedback_requirements: z.array(z.string().min(1)).default([]),
|
||||
activity: z.array(externalWorkOrderActivitySchema).default([]),
|
||||
origin: z.literal("synthetic"),
|
||||
origin: z.literal("system_data"),
|
||||
updated_at: workbenchDateTimeSchema
|
||||
}).strict());
|
||||
const taskQuestionAnswerSchema = z.object({ question_id: z.string().min(1).max(128),
|
||||
selected_option_ids: z.array(z.string().min(1).max(128)).max(12), custom_text: z.string().max(2000) }).strict();
|
||||
const taskQuestionRequestSchema = z.object({
|
||||
question_request_id: z.string().uuid(), task_id: z.string().uuid(), run_id: z.string().uuid(),
|
||||
execution_generation: z.number().int().positive(), source_session_id: z.string(),
|
||||
status: z.enum(["pending", "answered", "cancelled"]), version: z.number().int().positive(),
|
||||
created_at: workbenchDateTimeSchema, answered_at: workbenchDateTimeSchema.nullable(), answered_by: z.string().nullable(),
|
||||
questions: z.array(z.object({ question_id: z.string().min(1).max(128), title: z.string().min(1).max(200), body: z.string().min(1).max(2000),
|
||||
options: z.array(z.object({ id: z.string().min(1).max(128), label: z.string().min(1).max(200) }).strict()).max(12),
|
||||
mode: z.enum(["single", "multiple"]), allow_custom: z.boolean(), required: z.boolean() }).strict()).min(1).max(3),
|
||||
answers: z.array(taskQuestionAnswerSchema).max(3)
|
||||
}).strict();
|
||||
export type TaskQuestionRequest = z.infer<typeof taskQuestionRequestSchema>;
|
||||
export type TaskQuestionAnswer = z.infer<typeof taskQuestionAnswerSchema>;
|
||||
export type AnswerTaskQuestion = (questionId: string, version: number, answers: TaskQuestionAnswer[], requestId: string) => Promise<unknown>;
|
||||
|
||||
const operationalTaskSchema = taskSummarySchema.extend({
|
||||
latest_plan: planSnapshotSchema.nullable(),
|
||||
latest_report: reportRevisionSchema.nullable(),
|
||||
@@ -231,6 +248,7 @@ const operationalTaskSchema = taskSummarySchema.extend({
|
||||
evidence: z.array(evidenceSchema),
|
||||
actions: z.array(actionSchema),
|
||||
access_requests: z.array(accessRequestSchema).default([]),
|
||||
questions: z.array(taskQuestionRequestSchema).optional(),
|
||||
permissions: taskPermissionsSchema,
|
||||
work_order_snapshot: externalWorkOrderSnapshotSchema.nullable().default(null)
|
||||
}).strict();
|
||||
@@ -252,7 +270,7 @@ 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_type: z.enum(["task", "run", "access_request", "action", "question"]).default("task"),
|
||||
subject_id: z.string().uuid().nullable().default(null),
|
||||
report_reference: z.object({ execution_generation: z.number().int().positive(), revision: z.number().int().positive() }).strict().nullish(),
|
||||
resolved_at: workbenchDateTimeSchema.nullable().default(null),
|
||||
@@ -451,6 +469,39 @@ export async function fetchOperationalTaskPresentationCursor(taskId: string, get
|
||||
));
|
||||
}
|
||||
|
||||
export async function fetchOperationalTaskPresentationHistory(
|
||||
taskId: string,
|
||||
through: number,
|
||||
getAccessToken?: WorkbenchAccess,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
const items: InvestigationPresentationHistoryEvent[] = [];
|
||||
let after = 0;
|
||||
while (true) {
|
||||
signal?.throwIfAborted();
|
||||
const page = investigationPresentationHistoryPageSchema.parse(
|
||||
await operationalTaskRequest(
|
||||
`/operational-tasks/${encodeURIComponent(taskId)}/presentation-events?after=${after}&through=${through}&limit=100`,
|
||||
getAccessToken,
|
||||
{ signal }
|
||||
)
|
||||
);
|
||||
if (page.task_id !== taskId || page.event_cursor !== through)
|
||||
throw new Error("调查展示历史与所选任务或游标不一致");
|
||||
let previous = after;
|
||||
for (const item of page.items) {
|
||||
if (item.event_seq <= previous || item.event_seq > through)
|
||||
throw new Error("调查展示历史顺序不合法");
|
||||
previous = item.event_seq;
|
||||
items.push({ ...item, task_id: taskId });
|
||||
}
|
||||
if (page.next_after === null) return items;
|
||||
if (page.next_after !== previous || previous <= after)
|
||||
throw new Error("调查展示历史分页没有前进");
|
||||
after = previous;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOperationalTask(input: CreateOperationalTaskInput, getAccessToken?: WorkbenchAccess) {
|
||||
return operationalTaskSchema.parse(await operationalTaskRequest(
|
||||
"/operational-tasks",
|
||||
@@ -572,3 +623,13 @@ export async function fetchOperationalTaskEvidenceSnapshot(taskId: string, evide
|
||||
export function createOperationalRequestId() {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
|
||||
export async function answerOperationalTaskQuestion(taskId: string, questionId: string,
|
||||
version: number, answers: TaskQuestionAnswer[], requestId: string, getAccessToken?: WorkbenchAccess) {
|
||||
return operationalTaskSchema.parse(await operationalTaskRequest(
|
||||
`/operational-tasks/${encodeURIComponent(taskId)}/questions/${encodeURIComponent(questionId)}/answer`,
|
||||
getAccessToken, { method: "POST", body: JSON.stringify({ request_id: requestId,
|
||||
expected_version: version, answers: z.array(taskQuestionAnswerSchema).max(3).parse(answers) }) }
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user