import { apiRequest, getAppBaseUrl } from './common.ts' // ============================================================================ // Types // ============================================================================ /** * The only application kind today. Workstation is the operator-facing surface where a * canvas or workflow is run as tasks. */ export type ApplicationKey = 'workstation' /** * Which prompt version the application runs. * * `'promoted'` and `'production'` are logical names resolved server-side at create/update time and * stored as the concrete version id. Pass a version id to pin the application to it. */ export type ApplicationVersionTarget = 'promoted' | 'production' | (string & {}) /** * Input field the application exposes. Derived server-side from the target prompt version's * variables — do not build it by hand. */ export interface ApplicationVariable { name: string isRequired: boolean isMultimodal: boolean } export interface ApplicationConfig { approvalRequired: boolean isHidden: boolean variables?: ApplicationVariable[] } export interface Application { id: string key: ApplicationKey title: string description: string | null promptId: string /** Always a concrete version id once stored, even when created with `'production'`. */ usedVersion: string config: ApplicationConfig createdAt: string updatedAt: string deletedAt: string | null } export interface CreateApplicationPayload { title: string promptId: string usedVersion: ApplicationVersionTarget description?: string key?: ApplicationKey config?: Partial } export interface UpdateApplicationPayload { title?: string description?: string usedVersion?: ApplicationVersionTarget config?: Partial } // ============================================================================ // API Functions // ============================================================================ /** * List the workspace's applications. */ export async function listApplications(options?: { promptId?: string }): Promise { const applications = await apiRequest('/prompt-application') const list = Array.isArray(applications) ? applications : applications.data return options?.promptId ? list.filter(app => app.promptId === options.promptId) : list } /** * Find the workstation application for a canvas or workflow, or null when it has none. * * A prompt has at most one application per key, so this is unambiguous. */ export async function getWorkstation(promptId: string): Promise { const applications = await listApplications({ promptId }) return applications.find(app => app.key === 'workstation') ?? null } /** * Create a workstation application over a canvas or workflow. * * `config.variables` is derived server-side from the target version's variables; supplying it is * unnecessary. A prompt can only have one application per key — creating a second violates the * `(promptId, key)` unique index, so call {@link getWorkstation} first when the app may exist. */ export async function createApplication(payload: CreateApplicationPayload): Promise { return apiRequest('/prompt-application', { method: 'POST', body: JSON.stringify({ key: payload.key ?? 'workstation', title: payload.title, description: payload.description ?? null, promptId: payload.promptId, usedVersion: payload.usedVersion, config: { approvalRequired: payload.config?.approvalRequired ?? false, isHidden: payload.config?.isHidden ?? false, }, }), }) } /** * Create the workstation for a prompt, or update the existing one — the create-or-update the * publish flow performs. * * The prompt must already have a promoted version when `usedVersion` is a logical name. With nothing * promoted the API answers `404 Resource not found /prompt-application`, naming the collection rather * than the version it could not resolve. */ export async function upsertWorkstation( promptId: string, options: { title: string usedVersion?: ApplicationVersionTarget description?: string approvalRequired?: boolean isHidden?: boolean }, ): Promise { const existing = await getWorkstation(promptId) const usedVersion = options.usedVersion ?? 'production' if (existing) { return updateApplication(existing.id, { usedVersion, config: { approvalRequired: options.approvalRequired ?? Boolean(existing.config.approvalRequired), isHidden: options.isHidden ?? Boolean(existing.config.isHidden), }, }) } return createApplication({ title: options.title, promptId, usedVersion, description: options.description, config: { approvalRequired: options.approvalRequired ?? false, isHidden: options.isHidden ?? false, }, }) } export async function updateApplication( applicationId: string, payload: UpdateApplicationPayload, ): Promise { return apiRequest(`/prompt-application/${applicationId}`, { method: 'PATCH', body: JSON.stringify(payload), }) } export async function deleteApplication(applicationId: string): Promise { await apiRequest(`/prompt-application/${applicationId}`, { method: 'DELETE' }) } /** * Resolve the prompt version the application currently runs. */ export async function getApplicationTargetVersion(applicationId: string): Promise<{ id: string, title: string }> { return apiRequest(`/prompt-application/${applicationId}/targetPromptVersion`) } /** * Fetch one application. * * There is no `GET /prompt-application/:id` route, so this filters the list. */ export async function getApplication(applicationId: string): Promise { const applications = await listApplications() return applications.find(app => app.id === applicationId) ?? null } /** * The application's input fields, as the Workstation form renders them. * * These are the variable names a task must supply, and `isMultimodal` tells you which are files. * The list is derived server-side from the target version's variables — it is not something you set. */ export async function getApplicationVariables(applicationId: string): Promise { const application = await getApplication(applicationId) if (!application) throw new Error(`Application ${applicationId} not found`) return application.config?.variables ?? [] } /** * Link to the Workstation of the canvas or workflow the application belongs to. * * Workstation is reached through the prompt, not the application id. */ export function getWorkstationUrl(promptId: string): string { return `${getAppBaseUrl()}/prompt/${promptId}/workstation` }