package com.superbiz.agent.controller.sse; import com.fasterxml.jackson.annotation.JsonProperty; import com.superbiz.agent.harness.application.ChatApplicationContent; import com.superbiz.agent.harness.application.ChatApplicationStatus; import com.superbiz.agent.harness.application.ChatContentType; import com.superbiz.agent.harness.application.ChatFailureCode; import com.superbiz.agent.harness.contract.ReleaseOutcome; import java.util.Objects; public interface ChatSseEvent { record Metadata( @JsonProperty("session_id") String sessionId, @JsonProperty("run_id") String runId) implements ChatSseEvent { public Metadata { requireText(sessionId, "sessionId"); requireText(runId, "runId"); } } record Status(String code, String message) implements ChatSseEvent { public Status { requireText(code, "code"); requireText(message, "message"); } public static Status from(ChatApplicationStatus status) { Objects.requireNonNull(status, "status must not be null"); return new Status(status.name(), status.message()); } } record Content( @JsonProperty("content_type") ChatContentType contentType, @JsonProperty("payload") ChatApplicationContent payload) implements ChatSseEvent { public Content { Objects.requireNonNull(contentType, "contentType must not be null"); Objects.requireNonNull(payload, "payload must not be null"); if (contentType != payload.contentType()) { throw new IllegalArgumentException("contentType does not match payload"); } } } record Failure(ChatFailureCode code, String message) implements ChatSseEvent { public Failure { Objects.requireNonNull(code, "code must not be null"); requireText(message, "message"); } } record Done(ReleaseOutcome outcome) implements ChatSseEvent { public Done { Objects.requireNonNull(outcome, "outcome must not be null"); if (outcome == ReleaseOutcome.CANCELLED) { throw new IllegalArgumentException("CANCELLED is not a public SSE outcome"); } } } private static void requireText(String value, String name) { if (value == null || value.isBlank()) { throw new IllegalArgumentException(name + " must not be blank"); } } }