|
|
|
@@ -2,6 +2,7 @@ import { env } from "@/shared/config/env";
|
|
|
|
|
import type { AccessTokenProvider } from "@/shared/auth/keycloak-auth";
|
|
|
|
|
|
|
|
|
|
export type AgentRunStatus = "running" | "completed" | "error" | "aborted";
|
|
|
|
|
export type AgentSessionPurpose = "ordinary_chat" | "task_execution" | "task_collaboration";
|
|
|
|
|
|
|
|
|
|
export type AgentEventTriggerContext = {
|
|
|
|
|
schema_version: "agent-trigger@1";
|
|
|
|
@@ -51,9 +52,12 @@ export type AgentChatSession = {
|
|
|
|
|
created?: boolean;
|
|
|
|
|
event_duplicate?: boolean;
|
|
|
|
|
trigger_id?: string;
|
|
|
|
|
purpose?: AgentSessionPurpose;
|
|
|
|
|
task_id?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type AgentChatSessionSummary = {
|
|
|
|
|
trigger?: { subjectId: string; workflow: "water_quality_complaint"; occurredAt: string };
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
createdAt: number;
|
|
|
|
@@ -62,6 +66,8 @@ export type AgentChatSessionSummary = {
|
|
|
|
|
parentSessionId?: string;
|
|
|
|
|
isStreaming?: boolean;
|
|
|
|
|
runStatus?: AgentRunStatus;
|
|
|
|
|
purpose: AgentSessionPurpose;
|
|
|
|
|
taskId?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type AgentLoadedChatSession = AgentChatSessionSummary & {
|
|
|
|
@@ -71,6 +77,7 @@ export type AgentLoadedChatSession = AgentChatSessionSummary & {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type AgentSessionStreamDataEventType =
|
|
|
|
|
| "execution_plan"
|
|
|
|
|
| "token"
|
|
|
|
|
| "progress"
|
|
|
|
|
| "todo_update"
|
|
|
|
@@ -90,6 +97,7 @@ export type AgentSessionStreamDataEventType =
|
|
|
|
|
export type AgentSessionStreamEvent =
|
|
|
|
|
| {
|
|
|
|
|
type: "state";
|
|
|
|
|
executionPlans?: unknown[];
|
|
|
|
|
sessionId: string;
|
|
|
|
|
messages: unknown[];
|
|
|
|
|
isStreaming: boolean;
|
|
|
|
@@ -103,7 +111,8 @@ export type AgentSessionStreamEvent =
|
|
|
|
|
|
|
|
|
|
export type AgentApiClient = {
|
|
|
|
|
createSession: (options?: { triggerContext?: AgentEventTriggerContext }) => Promise<AgentChatSession>;
|
|
|
|
|
listSessions: () => Promise<AgentChatSessionSummary[]>;
|
|
|
|
|
listSessions: (options?: { purpose?: AgentSessionPurpose; taskId?: string }) => Promise<AgentChatSessionSummary[]>;
|
|
|
|
|
createTaskCollaborationSession: (taskId: string) => Promise<AgentChatSession>;
|
|
|
|
|
loadSession: (sessionId: string) => Promise<AgentLoadedChatSession | null>;
|
|
|
|
|
streamSession: (
|
|
|
|
|
sessionId: string,
|
|
|
|
@@ -184,11 +193,23 @@ export function createAgentApiClient(
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async listSessions() {
|
|
|
|
|
const payload = await requestJson<{ sessions?: unknown[] }>("/sessions");
|
|
|
|
|
async listSessions(listOptions) {
|
|
|
|
|
const params = new URLSearchParams();
|
|
|
|
|
if (listOptions?.purpose) params.set("purpose", listOptions.purpose);
|
|
|
|
|
if (listOptions?.taskId) params.set("task_id", listOptions.taskId);
|
|
|
|
|
const payload = await requestJson<{ sessions?: unknown[] }>(
|
|
|
|
|
`/sessions${params.size ? `?${params.toString()}` : ""}`
|
|
|
|
|
);
|
|
|
|
|
return (payload.sessions ?? []).map(toSessionSummary).filter(isPresent).sort(compareSessionSummaries);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async createTaskCollaborationSession(taskId) {
|
|
|
|
|
return requestJson<AgentChatSession>(
|
|
|
|
|
`/task/${encodeURIComponent(taskId)}/collaboration/session`,
|
|
|
|
|
{ method: "POST" }
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async getFrontendActionRegistry() {
|
|
|
|
|
return requestJson<unknown>("/frontend-action-registry");
|
|
|
|
|
},
|
|
|
|
@@ -432,6 +453,10 @@ function readRunStatus(value: unknown): AgentRunStatus | undefined {
|
|
|
|
|
: undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readSessionPurpose(value: unknown): AgentSessionPurpose {
|
|
|
|
|
return value === "task_execution" || value === "task_collaboration" ? value : "ordinary_chat";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toSessionSummary(value: unknown): AgentChatSessionSummary | null {
|
|
|
|
|
if (!isRecord(value)) {
|
|
|
|
|
return null;
|
|
|
|
@@ -450,7 +475,14 @@ function toSessionSummary(value: unknown): AgentChatSessionSummary | null {
|
|
|
|
|
status: typeof value.status === "string" ? value.status : undefined,
|
|
|
|
|
parentSessionId: typeof value.parent_session_id === "string" ? value.parent_session_id : undefined,
|
|
|
|
|
isStreaming: typeof value.is_streaming === "boolean" ? value.is_streaming : undefined,
|
|
|
|
|
runStatus: readRunStatus(value.run_status)
|
|
|
|
|
runStatus: readRunStatus(value.run_status),
|
|
|
|
|
purpose: readSessionPurpose(value.purpose),
|
|
|
|
|
taskId: typeof value.task_id === "string" ? value.task_id : undefined,
|
|
|
|
|
trigger: isRecord(value.trigger) && value.trigger.workflow === "water_quality_complaint" &&
|
|
|
|
|
typeof value.trigger.subject_id === "string" && typeof value.trigger.occurred_at === "string" &&
|
|
|
|
|
Number.isFinite(Date.parse(value.trigger.occurred_at))
|
|
|
|
|
? { subjectId: value.trigger.subject_id, workflow: "water_quality_complaint", occurredAt: value.trigger.occurred_at }
|
|
|
|
|
: undefined
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -530,6 +562,7 @@ function emitSessionSseEvent(
|
|
|
|
|
const sessionId = typeof data.session_id === "string" ? data.session_id : "";
|
|
|
|
|
onEvent({
|
|
|
|
|
type: "state",
|
|
|
|
|
executionPlans: Array.isArray(data.execution_plans) ? data.execution_plans : undefined,
|
|
|
|
|
sessionId,
|
|
|
|
|
messages: Array.isArray(data.messages) ? data.messages : [],
|
|
|
|
|
isStreaming: data.is_streaming === true,
|
|
|
|
@@ -554,6 +587,7 @@ function isSessionStreamDataEventType(value: string): value is AgentSessionStrea
|
|
|
|
|
value === "token" ||
|
|
|
|
|
value === "progress" ||
|
|
|
|
|
value === "todo_update" ||
|
|
|
|
|
value === "execution_plan" ||
|
|
|
|
|
value === "permission_request" ||
|
|
|
|
|
value === "permission_response" ||
|
|
|
|
|
value === "question_request" ||
|
|
|
|
|