import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import type { RequestTraceV1Outcome as RequestTraceOutcome } from '@/lib/copilot/generated/request-trace-v1' import { RequestTraceV1Outcome, RequestTraceV1SpanStatus, } from '@/lib/copilot/generated/request-trace-v1' import { CopilotTransport } from '@/lib/copilot/generated/trace-attribute-values-v1' import type { CopilotLifecycleOptions } from '@/lib/copilot/request/lifecycle/run' import { runCopilotLifecycle } from '@/lib/copilot/request/lifecycle/run' import { withCopilotOtelContext } from '@/lib/copilot/request/otel' import { TraceCollector } from '@/lib/copilot/request/trace' import type { OrchestratorResult } from '@/lib/copilot/request/types' const logger = createLogger('CopilotHeadlessLifecycle') export async function runHeadlessCopilotLifecycle( requestPayload: Record, options: CopilotLifecycleOptions ): Promise { const simRequestId = typeof options.simRequestId === 'string' && options.simRequestId.length > 0 ? options.simRequestId : typeof requestPayload.messageId === 'string' && requestPayload.messageId.length > 0 ? requestPayload.messageId : generateId() const trace = new TraceCollector() const requestSpan = trace.startSpan('Headless Sim Agent Request', 'request', { route: options.goRoute, workflowId: options.workflowId, workspaceId: options.workspaceId, chatId: options.chatId, }) let result: OrchestratorResult | undefined let outcome: RequestTraceOutcome = RequestTraceV1Outcome.error return withCopilotOtelContext( { requestId: simRequestId, route: options.goRoute, chatId: options.chatId, workflowId: options.workflowId, executionId: options.executionId, runId: options.runId, transport: CopilotTransport.Headless, }, async (otelContext) => { try { result = await runCopilotLifecycle(requestPayload, { ...options, trace, simRequestId, otelContext, }) outcome = result.success ? RequestTraceV1Outcome.success : options.abortSignal?.aborted || result.cancelled ? RequestTraceV1Outcome.cancelled : RequestTraceV1Outcome.error return result } catch (error) { outcome = options.abortSignal?.aborted ? RequestTraceV1Outcome.cancelled : RequestTraceV1Outcome.error throw error } finally { trace.endSpan( requestSpan, outcome === RequestTraceV1Outcome.success ? RequestTraceV1SpanStatus.ok : outcome === RequestTraceV1Outcome.cancelled ? RequestTraceV1SpanStatus.cancelled : RequestTraceV1SpanStatus.error ) } } ) }