Use real IDE authoring session
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-16 20:14:38 +03:00
parent 5b26c67947
commit 3b37a217a8
2 changed files with 67 additions and 23 deletions
@@ -39,6 +39,7 @@ import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { import {
applyAuthoringChangeSet, applyAuthoringChangeSet,
ensureAuthoringSession,
getAuthoringSemanticDiffPreview, getAuthoringSemanticDiffPreview,
applyAuthoringMetadataObject, applyAuthoringMetadataObject,
applyAuthoringRollback, applyAuthoringRollback,
@@ -2048,8 +2049,7 @@ function EditorPanel({
routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null, routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null,
original_text: data.editorSourceText, original_text: data.editorSourceText,
proposed_text: nextProposedText, proposed_text: nextProposedText,
task_id: "task.preview", ...(await ensureAuthoringSession(data.projectId, data.apiUrl))
session_id: "session.preview"
}, },
data.apiUrl data.apiUrl
); );
@@ -2175,6 +2175,7 @@ function EditorPanel({
const apiUrl = const apiUrl =
data.apiUrl ?? data.apiUrl ??
(typeof window === "undefined" ? resolveApiUrl() : resolveApiUrl(window.location.host)); (typeof window === "undefined" ? resolveApiUrl() : resolveApiUrl(window.location.host));
const authoringSession = await ensureAuthoringSession(data.projectId, apiUrl);
const response = await applyAuthoringChangeSet( const response = await applyAuthoringChangeSet(
data.projectId, data.projectId,
{ {
@@ -2182,12 +2183,12 @@ function EditorPanel({
routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null, routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null,
original_text: data.editorSourceText ?? sourceText, original_text: data.editorSourceText ?? sourceText,
proposed_text: proposedText ?? sourceText, proposed_text: proposedText ?? sourceText,
task_id: null, task_id: authoringSession.task_id,
session_id: "session.ide", session_id: authoringSession.session_id,
user_id: "current-user", user_id: authoringSession.user_id,
estimated_tokens: 2550, estimated_tokens: 2550,
expected_next_version_id: versionPreview.next_version_id, expected_next_version_id: versionPreview.next_version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.guardedApplyNote, approval_note: t.guardedApplyNote,
apply_to_production: false apply_to_production: false
}, },
@@ -2200,7 +2201,7 @@ function EditorPanel({
status: response.status, status: response.status,
target: response.preview.target, target: response.preview.target,
version_id: response.version.version_id, version_id: response.version.version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.guardedApplyNote, approval_note: t.guardedApplyNote,
task_id: response.version.task_id, task_id: response.version.task_id,
session_id: response.version.session_id, session_id: response.version.session_id,
@@ -3261,10 +3262,7 @@ function MetadataDesignerPanel({
.map((command) => ({ .map((command) => ({
name: command.name.trim(), name: command.name.trim(),
handler: command.handler.trim() || null handler: command.handler.trim() || null
})), }))
task_id: null,
session_id: "session.ide.metadata",
user_id: "current-user"
}; };
const [draftState, setDraftState] = useState<"idle" | "previewing" | "applying" | "applied" | "error">("idle"); const [draftState, setDraftState] = useState<"idle" | "previewing" | "applying" | "applied" | "error">("idle");
const [draftMessage, setDraftMessage] = useState(""); const [draftMessage, setDraftMessage] = useState("");
@@ -3311,15 +3309,17 @@ function MetadataDesignerPanel({
const apiUrl = const apiUrl =
data.apiUrl ?? data.apiUrl ??
(typeof window === "undefined" ? resolveApiUrl() : resolveApiUrl(window.location.host)); (typeof window === "undefined" ? resolveApiUrl() : resolveApiUrl(window.location.host));
const preview = await getAuthoringMetadataObjectPreview(data.projectId, metadataDraft, apiUrl); const authoringSession = await ensureAuthoringSession(data.projectId, apiUrl);
const sessionDraft = { ...metadataDraft, ...authoringSession };
const preview = await getAuthoringMetadataObjectPreview(data.projectId, sessionDraft, apiUrl);
setDraftDiff(preview.semantic_diff); setDraftDiff(preview.semantic_diff);
setDraftState("applying"); setDraftState("applying");
const response = await applyAuthoringMetadataObject( const response = await applyAuthoringMetadataObject(
data.projectId, data.projectId,
{ {
...metadataDraft, ...sessionDraft,
expected_next_version_id: preview.version_preview.next_version_id, expected_next_version_id: preview.version_preview.next_version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.metadataDraftDescription, approval_note: t.metadataDraftDescription,
apply_to_production: false apply_to_production: false
}, },
@@ -3332,7 +3332,7 @@ function MetadataDesignerPanel({
status: response.status, status: response.status,
target: response.preview.target, target: response.preview.target,
version_id: response.version.version_id, version_id: response.version.version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.metadataDraftDescription, approval_note: t.metadataDraftDescription,
task_id: response.version.task_id, task_id: response.version.task_id,
session_id: response.version.session_id, session_id: response.version.session_id,
@@ -4469,15 +4469,16 @@ function HistoryPanel({
setRollbackState("applying"); setRollbackState("applying");
setRollbackMessage(""); setRollbackMessage("");
try { try {
const authoringSession = await ensureAuthoringSession(data.projectId, data.apiUrl);
const response = await applyAuthoringRollback( const response = await applyAuthoringRollback(
data.projectId, data.projectId,
rollbackPreview.change_id, rollbackPreview.change_id,
{ {
expected_rollback_version_id: rollbackPreview.rollback_version_id, expected_rollback_version_id: rollbackPreview.rollback_version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.rollbackApplyNote, approval_note: t.rollbackApplyNote,
task_id: null, task_id: authoringSession.task_id,
session_id: "session.ide.rollback", session_id: authoringSession.session_id,
apply_to_production: false apply_to_production: false
}, },
data.apiUrl data.apiUrl
@@ -4489,7 +4490,7 @@ function HistoryPanel({
status: response.status, status: response.status,
target: response.preview.target, target: response.preview.target,
version_id: response.version.version_id, version_id: response.version.version_id,
approved_by: "current-user", approved_by: authoringSession.user_id,
approval_note: t.rollbackApplyNote, approval_note: t.rollbackApplyNote,
task_id: response.version.task_id, task_id: response.version.task_id,
session_id: response.version.session_id, session_id: response.version.session_id,
+47 -4
View File
@@ -389,6 +389,7 @@ export type AuthoringSemanticDiffPreviewRequest = {
source_path?: string | null; source_path?: string | null;
task_id?: string | null; task_id?: string | null;
session_id?: string | null; session_id?: string | null;
user_id?: string | null;
}; };
export type AuthoringSemanticDiffPreview = { export type AuthoringSemanticDiffPreview = {
@@ -581,6 +582,12 @@ export type AuthoringChangeSummary = {
production_applied: boolean; production_applied: boolean;
}; };
export type AuthoringSessionContext = {
user_id: string;
task_id: string;
session_id: string;
};
export function resolveApiUrl(hostHeader?: string | null) { export function resolveApiUrl(hostHeader?: string | null) {
const configuredUrl = process.env.SFERA_API_URL ?? process.env.NEXT_PUBLIC_SFERA_API_URL; const configuredUrl = process.env.SFERA_API_URL ?? process.env.NEXT_PUBLIC_SFERA_API_URL;
if (configuredUrl) { if (configuredUrl) {
@@ -686,6 +693,39 @@ async function postOptionalJson<T>(apiUrl: string, path: string, body: unknown,
} }
} }
function ideAuthoringSessionContext(projectId: string): AuthoringSessionContext {
const safeProjectId = projectId.replace(/[^A-Za-z0-9_.-]/g, "-");
return {
user_id: "ide.developer",
task_id: `task.ide.${safeProjectId}`,
session_id: `session.ide.${safeProjectId}`
};
}
export async function ensureAuthoringSession(projectId: string, apiUrl = resolveApiUrl()): Promise<AuthoringSessionContext> {
const context = ideAuthoringSessionContext(projectId);
await postJson(apiUrl, "/collaboration/users", {
user_id: context.user_id,
display_name: "SFERA IDE"
});
await postJson(apiUrl, `/security/users/${encodeURIComponent(context.user_id)}/roles/developer`, {});
await postJson(apiUrl, "/collaboration/tasks", {
task_id: context.task_id,
project_id: projectId,
title: "SFERA IDE authoring",
status: "IN_PROGRESS",
assignee_user_id: context.user_id
});
await postJson(apiUrl, "/collaboration/sessions", {
session: {
session_id: context.session_id,
task_id: context.task_id,
user_id: context.user_id
}
});
return context;
}
export async function getDashboardData(apiUrl = resolveApiUrl()) { export async function getDashboardData(apiUrl = resolveApiUrl()) {
const [health, summary, snapshots, neo4j, aiUsage, aiPolicy] = await Promise.all([ const [health, summary, snapshots, neo4j, aiUsage, aiPolicy] = await Promise.all([
getJson<Health>(apiUrl, "/health"), getJson<Health>(apiUrl, "/health"),
@@ -874,6 +914,9 @@ export async function getProjectWorkspaceData(projectId: string, apiUrl = resolv
: ""; : "";
const editorSelectedObject = selectedObjectName ?? snapshotModule?.qualified_name ?? null; const editorSelectedObject = selectedObjectName ?? snapshotModule?.qualified_name ?? null;
const editorSelectedRoutine = selectedModuleRoutine ?? selectedRoutineName ?? null; const editorSelectedRoutine = selectedModuleRoutine ?? selectedRoutineName ?? null;
const authoringSession = selectedObjectName && authoringSourceText
? await ensureAuthoringSession(projectId, apiUrl).catch(() => null)
: null;
const authoringPreview = needsObjectPanels && selectedObjectName && authoringSourceText const authoringPreview = needsObjectPanels && selectedObjectName && authoringSourceText
? await postOptionalJson<AuthoringCompletionPreview | null>( ? await postOptionalJson<AuthoringCompletionPreview | null>(
apiUrl, apiUrl,
@@ -883,8 +926,7 @@ export async function getProjectWorkspaceData(projectId: string, apiUrl = resolv
routine_name: selectedModuleRoutine, routine_name: selectedModuleRoutine,
source_path: selectedObjectModule?.source_path ?? null, source_path: selectedObjectModule?.source_path ?? null,
source_text: authoringSourceText, source_text: authoringSourceText,
task_id: "task.preview", user_id: authoringSession?.user_id ?? null
session_id: "session.preview"
}, },
null null
) )
@@ -900,8 +942,9 @@ export async function getProjectWorkspaceData(projectId: string, apiUrl = resolv
original_text: authoringSourceText, original_text: authoringSourceText,
proposed_text: authoringProposedText, proposed_text: authoringProposedText,
source_path: selectedObjectModule?.source_path ?? null, source_path: selectedObjectModule?.source_path ?? null,
task_id: "task.preview", task_id: authoringSession?.task_id ?? null,
session_id: "session.preview" session_id: authoringSession?.session_id ?? null,
user_id: authoringSession?.user_id ?? null
}, },
null null
) )