563 lines
18 KiB
TypeScript
563 lines
18 KiB
TypeScript
import type {
|
|
AsyncEvalRunStartResponse,
|
|
AsyncEvalRunStatusResponse,
|
|
AutoGenPersonalityCatalogResponse,
|
|
AutoGenHistoryResponse,
|
|
AutoGenHistoryRecord,
|
|
AutoGenMode,
|
|
AutoRunAnnotationsResponse,
|
|
AutoRunAnnotationRecord,
|
|
AutoRunDetailResponse,
|
|
AutoRunDialogResponse,
|
|
AutoRunHistoryResponse,
|
|
AutoRunPostAnalysisResponse,
|
|
AssistantAnnotationsResponse,
|
|
AssistantAnnotationRecord,
|
|
AssistantMessageResultState,
|
|
AssistantConversationItem,
|
|
ConnectionState,
|
|
HistoryItem,
|
|
ManualCaseDecision,
|
|
NormalizeResultState,
|
|
PromptState,
|
|
RuntimeRun
|
|
} from "../state/types";
|
|
|
|
const PREFIX = "/api";
|
|
|
|
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const response = await fetch(`${PREFIX}${path}`, {
|
|
...init,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...(init?.headers ?? {})
|
|
}
|
|
});
|
|
const payload = (await response.json()) as T & { error?: { message?: string } };
|
|
if (!response.ok) {
|
|
const message = (payload as { error?: { message?: string } }).error?.message ?? "Ошибка запроса";
|
|
throw new Error(message);
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
export const apiClient = {
|
|
async loadSharedConnectionConfig(): Promise<{
|
|
ok: boolean;
|
|
connection: Omit<ConnectionState, "apiKey"> | null;
|
|
updated_at: string | null;
|
|
exists: boolean;
|
|
}> {
|
|
return request("/llm/shared-connection");
|
|
},
|
|
|
|
async saveSharedConnectionConfig(connection: ConnectionState): Promise<{
|
|
ok: boolean;
|
|
connection: Omit<ConnectionState, "apiKey">;
|
|
updated_at: string;
|
|
}> {
|
|
return request("/llm/shared-connection", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
llmProvider: connection.llmProvider,
|
|
model: connection.model,
|
|
baseUrl: connection.baseUrl,
|
|
temperature: connection.temperature,
|
|
maxOutputTokens: connection.maxOutputTokens
|
|
})
|
|
});
|
|
},
|
|
|
|
async listModels(connection: ConnectionState): Promise<{ ok: boolean; models: string[]; count: number; timestamp: string }> {
|
|
return request("/llm/models", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
llmProvider: connection.llmProvider,
|
|
apiKey: connection.apiKey,
|
|
model: connection.model,
|
|
baseUrl: connection.baseUrl
|
|
})
|
|
});
|
|
},
|
|
|
|
async testConnection(connection: ConnectionState): Promise<{
|
|
ok: boolean;
|
|
provider: "openai" | "local";
|
|
model: string;
|
|
model_found: boolean | null;
|
|
models_count: number | null;
|
|
timestamp: string;
|
|
}> {
|
|
return request("/llm/test-connection", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
llmProvider: connection.llmProvider,
|
|
apiKey: connection.apiKey,
|
|
model: connection.model,
|
|
baseUrl: connection.baseUrl
|
|
})
|
|
});
|
|
},
|
|
|
|
async normalize(params: {
|
|
connection: ConnectionState;
|
|
prompts: PromptState;
|
|
promptVersion?: string;
|
|
query: {
|
|
userQuestion: string;
|
|
periodHint?: string;
|
|
businessContext?: string;
|
|
expectedRoute?: string;
|
|
};
|
|
saveAsTestCase?: boolean;
|
|
useMock?: boolean;
|
|
}): Promise<NormalizeResultState> {
|
|
return request("/normalize", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
llmProvider: params.connection.llmProvider,
|
|
apiKey: params.connection.apiKey,
|
|
model: params.connection.model,
|
|
baseUrl: params.connection.baseUrl,
|
|
temperature: params.connection.temperature,
|
|
maxOutputTokens: params.connection.maxOutputTokens,
|
|
promptVersion: params.promptVersion,
|
|
systemPrompt: params.prompts.systemPrompt,
|
|
developerPrompt: params.prompts.developerPrompt,
|
|
domainPrompt: params.prompts.domainPrompt,
|
|
fewShotExamples: params.prompts.fewShotExamples,
|
|
userQuestion: params.query.userQuestion,
|
|
context: {
|
|
period_hint: params.query.periodHint ?? "",
|
|
business_context: params.query.businessContext ?? "",
|
|
expected_route: params.query.expectedRoute ?? ""
|
|
},
|
|
saveAsTestCase: Boolean(params.saveAsTestCase),
|
|
useMock: Boolean(params.useMock)
|
|
})
|
|
});
|
|
},
|
|
|
|
async loadHistory(): Promise<{ ok: boolean; items: HistoryItem[] }> {
|
|
return request("/history");
|
|
},
|
|
|
|
async loadTrace(traceId: string): Promise<{ ok: boolean; trace: unknown }> {
|
|
return request(`/history/${traceId}`);
|
|
},
|
|
|
|
async loadPresets(): Promise<{
|
|
ok: boolean;
|
|
presets: Array<{
|
|
id: string;
|
|
name: string;
|
|
prompt_version: string;
|
|
systemPrompt: string;
|
|
developerPrompt: string;
|
|
domainPrompt: string;
|
|
schemaNotes?: string;
|
|
fewShotExamples?: string;
|
|
}>;
|
|
}> {
|
|
return request("/presets");
|
|
},
|
|
|
|
async savePreset(input: {
|
|
id?: string;
|
|
name: string;
|
|
prompt_version?: string;
|
|
systemPrompt: string;
|
|
developerPrompt: string;
|
|
domainPrompt: string;
|
|
schemaNotes?: string;
|
|
fewShotExamples?: string;
|
|
}): Promise<{ ok: boolean }> {
|
|
return request("/presets/save", {
|
|
method: "POST",
|
|
body: JSON.stringify(input)
|
|
});
|
|
},
|
|
|
|
async runEval(input: {
|
|
connection: ConnectionState;
|
|
prompts: PromptState;
|
|
promptVersion?: string;
|
|
caseIds?: string[];
|
|
useMock?: boolean;
|
|
mode?: "standard" | "single-pass-strict";
|
|
caseSetFile?: string;
|
|
rawQuestions?: string;
|
|
evalTarget?: "normalizer" | "assistant_stage1" | "assistant_stage2" | "assistant_p0";
|
|
compareWithReportFile?: string;
|
|
analysisDate?: string;
|
|
}): Promise<{ ok: boolean; report: unknown }> {
|
|
return request("/eval/run", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
normalizeConfig: {
|
|
llmProvider: input.connection.llmProvider,
|
|
apiKey: input.connection.apiKey,
|
|
model: input.connection.model,
|
|
baseUrl: input.connection.baseUrl,
|
|
temperature: input.connection.temperature,
|
|
maxOutputTokens: input.connection.maxOutputTokens,
|
|
promptVersion: input.promptVersion,
|
|
systemPrompt: input.prompts.systemPrompt,
|
|
developerPrompt: input.prompts.developerPrompt,
|
|
domainPrompt: input.prompts.domainPrompt,
|
|
fewShotExamples: input.prompts.fewShotExamples
|
|
},
|
|
caseIds: input.caseIds,
|
|
useMock: Boolean(input.useMock),
|
|
mode: input.mode ?? "standard",
|
|
caseSetFile: input.caseSetFile,
|
|
rawQuestions: input.rawQuestions,
|
|
eval_target: input.evalTarget,
|
|
compare_with_report_file: input.compareWithReportFile,
|
|
analysis_date: input.analysisDate
|
|
})
|
|
});
|
|
},
|
|
|
|
async startEvalRunAsync(input: {
|
|
connection: ConnectionState;
|
|
prompts: PromptState;
|
|
promptVersion?: string;
|
|
caseIds?: string[];
|
|
useMock?: boolean;
|
|
mode?: "standard" | "single-pass-strict";
|
|
caseSetFile?: string;
|
|
rawQuestions?: string;
|
|
evalTarget?: "normalizer" | "assistant_stage1" | "assistant_stage2" | "assistant_p0";
|
|
compareWithReportFile?: string;
|
|
questions?: string[];
|
|
scenarioQuestions?: string[];
|
|
scenarioTitle?: string;
|
|
analysisDate?: string;
|
|
}): Promise<AsyncEvalRunStartResponse> {
|
|
return request("/eval/run-async/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
normalizeConfig: {
|
|
llmProvider: input.connection.llmProvider,
|
|
apiKey: input.connection.apiKey,
|
|
model: input.connection.model,
|
|
baseUrl: input.connection.baseUrl,
|
|
temperature: input.connection.temperature,
|
|
maxOutputTokens: input.connection.maxOutputTokens,
|
|
promptVersion: input.promptVersion,
|
|
systemPrompt: input.prompts.systemPrompt,
|
|
developerPrompt: input.prompts.developerPrompt,
|
|
domainPrompt: input.prompts.domainPrompt,
|
|
fewShotExamples: input.prompts.fewShotExamples
|
|
},
|
|
caseIds: input.caseIds,
|
|
useMock: Boolean(input.useMock),
|
|
mode: input.mode ?? "standard",
|
|
caseSetFile: input.caseSetFile,
|
|
rawQuestions: input.rawQuestions,
|
|
eval_target: input.evalTarget,
|
|
compare_with_report_file: input.compareWithReportFile,
|
|
questions: input.questions,
|
|
scenarioQuestions: input.scenarioQuestions,
|
|
scenarioTitle: input.scenarioTitle,
|
|
analysis_date: input.analysisDate
|
|
})
|
|
});
|
|
},
|
|
|
|
async loadEvalRunAsyncStatus(jobId: string): Promise<AsyncEvalRunStatusResponse> {
|
|
return request(`/eval/run-async/${encodeURIComponent(jobId)}`);
|
|
},
|
|
|
|
async startRun(): Promise<{ ok: boolean; run: RuntimeRun; runId: string; sessionId: string; status: string }> {
|
|
return request("/accounting-agent/v1/runs/start", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
initiator: "ndc_operator",
|
|
source: "gui"
|
|
})
|
|
});
|
|
},
|
|
|
|
async finishRun(runId: string): Promise<{ ok: boolean; run: RuntimeRun }> {
|
|
return request("/accounting-agent/v1/runs/finish", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
runId,
|
|
status: "DONE",
|
|
source: "gui",
|
|
reason: "Остановлено оператором из GUI"
|
|
})
|
|
});
|
|
},
|
|
|
|
async listRuns(): Promise<{ ok: boolean; items: RuntimeRun[] }> {
|
|
return request("/accounting-agent/v1/runs");
|
|
},
|
|
|
|
async listResults(): Promise<{ ok: boolean; items: unknown[] }> {
|
|
return request("/accounting-agent/v1/results");
|
|
},
|
|
|
|
async runTrace(runId: string): Promise<{ ok: boolean; items: unknown[] }> {
|
|
return request(`/accounting-agent/v1/trace/run/${runId}`);
|
|
},
|
|
|
|
async sendAssistantMessage(input: {
|
|
connection: ConnectionState;
|
|
prompts: PromptState;
|
|
userMessage: string;
|
|
sessionId?: string;
|
|
promptVersion?: string;
|
|
context?: {
|
|
periodHint?: string;
|
|
businessContext?: string;
|
|
};
|
|
useMock?: boolean;
|
|
}): Promise<AssistantMessageResultState> {
|
|
return request("/assistant/message", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
session_id: input.sessionId ?? "",
|
|
mode: "assistant",
|
|
message: input.userMessage,
|
|
user_message: input.userMessage,
|
|
llmProvider: input.connection.llmProvider,
|
|
apiKey: input.connection.apiKey,
|
|
model: input.connection.model,
|
|
baseUrl: input.connection.baseUrl,
|
|
temperature: input.connection.temperature,
|
|
maxOutputTokens: input.connection.maxOutputTokens,
|
|
promptVersion: input.promptVersion ?? "address_query_runtime_v1",
|
|
systemPrompt: input.prompts.systemPrompt,
|
|
developerPrompt: input.prompts.developerPrompt,
|
|
domainPrompt: input.prompts.domainPrompt,
|
|
fewShotExamples: input.prompts.fewShotExamples,
|
|
context: {
|
|
period_hint: input.context?.periodHint ?? "",
|
|
business_context: input.context?.businessContext ?? ""
|
|
},
|
|
useMock: Boolean(input.useMock)
|
|
})
|
|
});
|
|
},
|
|
|
|
async loadAssistantSession(sessionId: string): Promise<{ ok: boolean; session: { items: AssistantConversationItem[] } }> {
|
|
return request(`/assistant/session/${sessionId}`);
|
|
},
|
|
|
|
async saveAutoRunAssistantSession(input: {
|
|
session_id: string;
|
|
title: string;
|
|
generated_by?: string;
|
|
context?: {
|
|
llm_provider?: string;
|
|
model?: string;
|
|
assistant_prompt_version?: string;
|
|
decomposition_prompt_version?: string;
|
|
prompt_fingerprint?: string;
|
|
};
|
|
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
|
|
return request("/autoruns/autogen/save-assistant-session", {
|
|
method: "POST",
|
|
body: JSON.stringify(input)
|
|
});
|
|
},
|
|
|
|
async loadAssistantAnnotations(input?: {
|
|
session_id?: string;
|
|
limit?: number;
|
|
}): Promise<AssistantAnnotationsResponse> {
|
|
const params = new URLSearchParams();
|
|
if (input?.session_id) params.set("session_id", input.session_id);
|
|
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
|
|
const query = params.toString();
|
|
return request(`/assistant/annotations${query ? `?${query}` : ""}`);
|
|
},
|
|
|
|
async saveAssistantAnnotation(input: {
|
|
session_id: string;
|
|
message_index: number;
|
|
rating: number;
|
|
comment: string;
|
|
annotation_author?: string;
|
|
}): Promise<{ ok: boolean; annotation: AssistantAnnotationRecord }> {
|
|
return request("/assistant/annotations", {
|
|
method: "POST",
|
|
body: JSON.stringify(input)
|
|
});
|
|
},
|
|
|
|
async loadAutoRunsHistory(input?: {
|
|
from?: string;
|
|
to?: string;
|
|
target?: string;
|
|
mode?: string;
|
|
use_mock?: "any" | "true" | "false";
|
|
prompt_contains?: string;
|
|
limit?: number;
|
|
scan_limit?: number;
|
|
}): Promise<AutoRunHistoryResponse> {
|
|
const params = new URLSearchParams();
|
|
if (input?.from) params.set("from", input.from);
|
|
if (input?.to) params.set("to", input.to);
|
|
if (input?.target) params.set("target", input.target);
|
|
if (input?.mode) params.set("mode", input.mode);
|
|
if (input?.use_mock) params.set("use_mock", input.use_mock);
|
|
if (input?.prompt_contains) params.set("prompt_contains", input.prompt_contains);
|
|
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
|
|
if (typeof input?.scan_limit === "number") params.set("scan_limit", String(input.scan_limit));
|
|
const query = params.toString();
|
|
return request(`/autoruns/history${query ? `?${query}` : ""}`);
|
|
},
|
|
|
|
async loadAutoRunDetail(runId: string): Promise<AutoRunDetailResponse> {
|
|
return request(`/autoruns/history/${encodeURIComponent(runId)}`);
|
|
},
|
|
|
|
async loadAutoRunCaseDialog(runId: string, caseId: string): Promise<AutoRunDialogResponse> {
|
|
return request(`/autoruns/history/${encodeURIComponent(runId)}/case/${encodeURIComponent(caseId)}/dialog`);
|
|
},
|
|
|
|
async loadAutoRunAnnotations(input?: {
|
|
run_id?: string;
|
|
case_id?: string;
|
|
min_rating?: number;
|
|
manual_case_decision?: ManualCaseDecision | "all";
|
|
limit?: number;
|
|
}): Promise<AutoRunAnnotationsResponse> {
|
|
const params = new URLSearchParams();
|
|
if (input?.run_id) params.set("run_id", input.run_id);
|
|
if (input?.case_id) params.set("case_id", input.case_id);
|
|
if (typeof input?.min_rating === "number") params.set("min_rating", String(input.min_rating));
|
|
if (input?.manual_case_decision) params.set("manual_case_decision", input.manual_case_decision);
|
|
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
|
|
const query = params.toString();
|
|
return request(`/autoruns/annotations${query ? `?${query}` : ""}`);
|
|
},
|
|
|
|
async saveAutoRunAnnotation(input: {
|
|
run_id: string;
|
|
case_id: string;
|
|
message_index: number;
|
|
rating: number;
|
|
comment: string;
|
|
manual_case_decision: ManualCaseDecision;
|
|
annotation_author?: string;
|
|
}): Promise<{ ok: boolean; annotation: AutoRunAnnotationRecord; case_annotation_stats: { count: number; latest_at: string | null; avg_rating: number | null } | null }> {
|
|
return request("/autoruns/annotations", {
|
|
method: "POST",
|
|
body: JSON.stringify(input)
|
|
});
|
|
},
|
|
|
|
async updateAutoRunAnnotation(input: {
|
|
annotation_id: string;
|
|
resolved: boolean;
|
|
resolved_by?: string;
|
|
}): Promise<{ ok: boolean; annotation: AutoRunAnnotationRecord; case_annotation_stats: { count: number; latest_at: string | null; avg_rating: number | null } | null }> {
|
|
return request(`/autoruns/annotations/${encodeURIComponent(input.annotation_id)}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify({
|
|
resolved: input.resolved,
|
|
resolved_by: input.resolved_by
|
|
})
|
|
});
|
|
},
|
|
|
|
async loadAutoRunPostAnalysis(input?: {
|
|
run_id?: string;
|
|
limit_per_queue?: number;
|
|
annotation_limit?: number;
|
|
scan_limit?: number;
|
|
from?: string;
|
|
to?: string;
|
|
target?: string;
|
|
mode?: string;
|
|
use_mock?: "any" | "true" | "false";
|
|
prompt_contains?: string;
|
|
}): Promise<AutoRunPostAnalysisResponse> {
|
|
const params = new URLSearchParams();
|
|
if (input?.run_id) params.set("run_id", input.run_id);
|
|
if (typeof input?.limit_per_queue === "number") params.set("limit_per_queue", String(input.limit_per_queue));
|
|
if (typeof input?.annotation_limit === "number") params.set("annotation_limit", String(input.annotation_limit));
|
|
if (typeof input?.scan_limit === "number") params.set("scan_limit", String(input.scan_limit));
|
|
if (input?.from) params.set("from", input.from);
|
|
if (input?.to) params.set("to", input.to);
|
|
if (input?.target) params.set("target", input.target);
|
|
if (input?.mode) params.set("mode", input.mode);
|
|
if (input?.use_mock) params.set("use_mock", input.use_mock);
|
|
if (input?.prompt_contains) params.set("prompt_contains", input.prompt_contains);
|
|
const query = params.toString();
|
|
return request(`/autoruns/post-analysis${query ? `?${query}` : ""}`);
|
|
},
|
|
|
|
async loadAutoRunAutogenHistory(input?: {
|
|
mode?: AutoGenMode;
|
|
limit?: number;
|
|
}): Promise<AutoGenHistoryResponse> {
|
|
const params = new URLSearchParams();
|
|
if (input?.mode) params.set("mode", input.mode);
|
|
if (typeof input?.limit === "number") params.set("limit", String(input.limit));
|
|
const query = params.toString();
|
|
return request(`/autoruns/autogen/history${query ? `?${query}` : ""}`);
|
|
},
|
|
|
|
async loadAutoRunAutogenPersonalityCatalog(): Promise<AutoGenPersonalityCatalogResponse> {
|
|
return request("/autoruns/autogen/personality-catalog");
|
|
},
|
|
|
|
async updateAutoRunAutogenQuestions(input: {
|
|
generation_id: string;
|
|
questions: string[];
|
|
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
|
|
return request(`/autoruns/autogen/history/${encodeURIComponent(input.generation_id)}/questions`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify({
|
|
questions: input.questions
|
|
})
|
|
});
|
|
},
|
|
|
|
async deleteAutoRunAutogenHistoryRecord(generationId: string): Promise<{
|
|
ok: boolean;
|
|
generation_id: string;
|
|
deleted_files: string[];
|
|
}> {
|
|
return request(`/autoruns/autogen/history/${encodeURIComponent(generationId)}`, {
|
|
method: "DELETE"
|
|
});
|
|
},
|
|
|
|
async generateAutoRunQuestions(input: {
|
|
mode: AutoGenMode;
|
|
count: number;
|
|
domain?: string;
|
|
persist_to_eval_cases?: boolean;
|
|
generated_by?: string;
|
|
llm?: {
|
|
llm_provider?: "openai" | "local";
|
|
api_key?: string;
|
|
model?: string;
|
|
base_url?: string;
|
|
temperature?: number;
|
|
max_output_tokens?: number;
|
|
};
|
|
context?: {
|
|
llm_provider?: string;
|
|
model?: string;
|
|
assistant_prompt_version?: string;
|
|
decomposition_prompt_version?: string;
|
|
prompt_fingerprint?: string;
|
|
autogen_personality_id?: string;
|
|
autogen_personality_prompt?: string;
|
|
};
|
|
}): Promise<{ ok: boolean; generation: AutoGenHistoryRecord }> {
|
|
return request("/autoruns/autogen/generate", {
|
|
method: "POST",
|
|
body: JSON.stringify(input)
|
|
});
|
|
}
|
|
};
|