001/* 002 * Copyright 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.soklet; 018 019import org.jspecify.annotations.NonNull; 020import org.jspecify.annotations.Nullable; 021 022import javax.annotation.concurrent.NotThreadSafe; 023import javax.annotation.concurrent.ThreadSafe; 024import java.util.List; 025import java.util.Objects; 026import java.util.Optional; 027 028/** 029 * Immutable output of one completed MCP prompt request. 030 * 031 * @author <a href="https://www.revetkn.com">Mark Allen</a> 032 */ 033@ThreadSafe 034public final class McpPromptOutput implements McpCompletePayload { 035 @Nullable 036 private final String description; 037 @NonNull 038 private final List<@NonNull McpPromptMessage> messages; 039 040 /** @return an empty prompt-output builder */ 041 @NonNull 042 public static Builder builder() { 043 return new Builder(); 044 } 045 046 /** 047 * Creates prompt output from messages. 048 * 049 * @param messages prompt messages 050 * @return immutable prompt output 051 */ 052 @NonNull 053 public static McpPromptOutput fromMessages( 054 @NonNull McpPromptMessage @NonNull... messages) { 055 return builder().messages(List.of(messages)).build(); 056 } 057 058 private McpPromptOutput(@NonNull Builder builder) { 059 this.description = builder.description; 060 this.messages = List.copyOf(builder.messages); 061 } 062 063 /** @return prompt description, if supplied */ 064 @NonNull 065 public Optional<@NonNull String> getDescription() { 066 return Optional.ofNullable(this.description); 067 } 068 069 /** @return immutable messages in insertion order */ 070 @NonNull 071 public List<@NonNull McpPromptMessage> getMessages() { 072 return this.messages; 073 } 074 075 /** @return whether the description and messages are structurally equal */ 076 @Override 077 public boolean equals(@Nullable Object other) { 078 if (this == other) 079 return true; 080 if (!(other instanceof McpPromptOutput output)) 081 return false; 082 return Objects.equals(this.description, output.description) 083 && this.messages.equals(output.messages); 084 } 085 086 /** @return structural prompt-output hash code */ 087 @Override 088 public int hashCode() { 089 return Objects.hash(this.description, this.messages); 090 } 091 092 /** 093 * Mutable builder for immutable {@link McpPromptOutput}. 094 * 095 * @author <a href="https://www.revetkn.com">Mark Allen</a> 096 */ 097 @NotThreadSafe 098 public static final class Builder { 099 @Nullable 100 private String description; 101 @NonNull 102 private List<@NonNull McpPromptMessage> messages = 103 List.of(); 104 105 private Builder() { 106 } 107 108 /** @param description exact prompt description, without normalization 109 * @return this builder 110 * @throws IllegalArgumentException if the description contains an unpaired surrogate */ 111 @NonNull 112 public Builder description(@NonNull String description) { 113 this.description = McpContentValueSupport.requireWellFormedString(description); 114 return this; 115 } 116 117 /** 118 * Replaces prompt messages in supplied order. 119 * Null or empty clears the property. The complete list is validated and 120 * snapshotted before replacing the prior value. 121 * 122 * @param messages prompt messages, or null to clear 123 * @return this builder 124 * @throws NullPointerException if a list element is null 125 */ 126 @NonNull 127 public Builder messages( 128 @Nullable List<@NonNull McpPromptMessage> messages) { 129 this.messages = messages == null ? List.of() 130 : List.copyOf(messages); 131 return this; 132 } 133 134 /** @return immutable prompt output */ 135 @NonNull 136 public McpPromptOutput build() { 137 return new McpPromptOutput(this); 138 } 139 } 140}