fix: preserve workspace evidence in browser drafts
This commit is contained in:
@@ -17,6 +17,49 @@ export interface CanonicalDiagnostics {
|
||||
dwh_rest?: RestDiagnosticRequest & { response: { database: string; schema: string } };
|
||||
}
|
||||
|
||||
export interface EvidencePolicy {
|
||||
max_chunk_chars: number;
|
||||
retain_published_generations: number;
|
||||
}
|
||||
|
||||
export type EvidenceSource =
|
||||
| {
|
||||
type: "filesystem";
|
||||
uri: string;
|
||||
patterns: string[];
|
||||
max_bytes: number;
|
||||
}
|
||||
| {
|
||||
type: "http";
|
||||
uris: string[];
|
||||
authentication: "none" | "signed_urls_file";
|
||||
connect_timeout_ms: number;
|
||||
read_timeout_ms: number;
|
||||
max_bytes: number;
|
||||
max_redirects: number;
|
||||
allow_private_hosts: boolean;
|
||||
max_cache_bytes: number;
|
||||
}
|
||||
| {
|
||||
type: "s3";
|
||||
uri: string;
|
||||
endpoint_url?: string;
|
||||
region?: string;
|
||||
credentials: "ambient" | "static_files";
|
||||
trusted_endpoint: boolean;
|
||||
allow_private_endpoint: boolean;
|
||||
allow_insecure_endpoint: boolean;
|
||||
max_bytes: number;
|
||||
max_objects: number;
|
||||
max_pages: number;
|
||||
page_size: number;
|
||||
};
|
||||
|
||||
export interface WorkspaceEvidence {
|
||||
source: EvidenceSource;
|
||||
policy: EvidencePolicy;
|
||||
}
|
||||
|
||||
export interface CanonicalWorkspace {
|
||||
workspace: {
|
||||
schema_version: 3;
|
||||
@@ -48,6 +91,7 @@ export interface CanonicalWorkspace {
|
||||
};
|
||||
llm_policy: { default?: `${string}/${string}`; allowed: `${string}/${string}`[] };
|
||||
diagnostics?: CanonicalDiagnostics;
|
||||
evidence?: WorkspaceEvidence;
|
||||
}
|
||||
|
||||
export interface WorkspaceRevision {
|
||||
@@ -132,6 +176,16 @@ const conflictFields = new Set([
|
||||
"diagnostics", "diagnostics.dwh_rest",
|
||||
"diagnostics.dwh_rest.method", "diagnostics.dwh_rest.path", "diagnostics.dwh_rest.auth",
|
||||
"diagnostics.dwh_rest.response.database", "diagnostics.dwh_rest.response.schema",
|
||||
"evidence", "evidence.source", "evidence.source.type", "evidence.source.uri",
|
||||
"evidence.source.patterns", "evidence.source.max_bytes", "evidence.source.uris",
|
||||
"evidence.source.authentication", "evidence.source.connect_timeout_ms",
|
||||
"evidence.source.read_timeout_ms", "evidence.source.max_redirects",
|
||||
"evidence.source.allow_private_hosts", "evidence.source.max_cache_bytes",
|
||||
"evidence.source.endpoint_url", "evidence.source.region", "evidence.source.credentials",
|
||||
"evidence.source.trusted_endpoint", "evidence.source.allow_private_endpoint",
|
||||
"evidence.source.allow_insecure_endpoint", "evidence.source.max_objects",
|
||||
"evidence.source.max_pages", "evidence.source.page_size", "evidence.policy",
|
||||
"evidence.policy.max_chunk_chars", "evidence.policy.retain_published_generations",
|
||||
]);
|
||||
|
||||
const workspaceErrorCodes = new Set<WorkspaceErrorCode>([
|
||||
@@ -193,20 +247,43 @@ export function asWorkspaceConflict(error: unknown): WorkspaceConflict | undefin
|
||||
};
|
||||
}
|
||||
|
||||
function requireCanonicalWorkspace(value: unknown): CanonicalWorkspace {
|
||||
const workspace = sanitizeCanonicalWorkspace(value);
|
||||
if (!workspace) throw new Error("Workspace API returned an invalid canonical workspace");
|
||||
return workspace;
|
||||
}
|
||||
|
||||
export const listWorkspaces = () => apiFetch<WorkspaceSummary[]>("/workspaces");
|
||||
export const getWorkspace = (id: string) => apiFetch<WorkspaceRecord>(`/workspaces/${encodeURIComponent(id)}`);
|
||||
export const getWorkspace = async (id: string): Promise<WorkspaceRecord> => {
|
||||
const response = await apiFetch<unknown>(`/workspaces/${encodeURIComponent(id)}`);
|
||||
const source = object(response);
|
||||
if (!source) throw new Error("Workspace API returned an invalid workspace record");
|
||||
return {
|
||||
workspace: requireCanonicalWorkspace(source.workspace),
|
||||
revision: source.revision as WorkspaceRevision,
|
||||
};
|
||||
};
|
||||
export const getWorkspaceRegistryStatus = () => apiFetch<WorkspaceRegistryStatus>("/workspace-registry/status");
|
||||
export const pullWorkspaceRegistry = () => apiFetch<WorkspaceRegistryStatus>("/workspace-registry/pull", { method: "POST" });
|
||||
export const validateWorkspace = (workspace: CanonicalWorkspace) =>
|
||||
apiFetch<{ workspace: CanonicalWorkspace; contract: unknown }>("/workspaces/validate", {
|
||||
method: "POST", body: JSON.stringify({ workspace }),
|
||||
export const validateWorkspace = async (workspace: CanonicalWorkspace) => {
|
||||
const safe = requireCanonicalWorkspace(workspace);
|
||||
const response = await apiFetch<unknown>("/workspaces/validate", {
|
||||
method: "POST", body: JSON.stringify({ workspace: safe }),
|
||||
});
|
||||
const source = object(response);
|
||||
if (!source) throw new Error("Workspace API returned an invalid validation result");
|
||||
return { workspace: requireCanonicalWorkspace(source.workspace), contract: source.contract };
|
||||
};
|
||||
export const testWorkspace = (id: string) =>
|
||||
apiFetch<WorkspaceDiagnostics>(`/workspaces/${encodeURIComponent(id)}/test`, { method: "POST" });
|
||||
export const publishWorkspace = (request: PublishWorkspaceRequest) =>
|
||||
apiFetch<{ revision: WorkspaceRevision } | undefined>("/workspaces/publish", {
|
||||
method: "POST", body: JSON.stringify(request),
|
||||
export const publishWorkspace = (request: PublishWorkspaceRequest) => {
|
||||
const safeRequest: PublishWorkspaceRequest = request.action === "delete"
|
||||
? request
|
||||
: { ...request, workspace: requireCanonicalWorkspace(request.workspace) };
|
||||
return apiFetch<{ revision: WorkspaceRevision } | undefined>("/workspaces/publish", {
|
||||
method: "POST", body: JSON.stringify(safeRequest),
|
||||
});
|
||||
};
|
||||
export const exportWorkspace = (id: string) =>
|
||||
apiFetchBlob(`/workspaces/${encodeURIComponent(id)}/export`);
|
||||
export const importWorkspace = (bundle: File) => {
|
||||
|
||||
Reference in New Issue
Block a user