001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2025-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.ai.dotprompt; 019 020import dev.enola.common.io.object.WithSchema; 021import dev.enola.common.template.Template; 022 023import org.jspecify.annotations.Nullable; 024 025import java.net.URI; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.Map; 029import java.util.Set; 030 031/** 032 * Dot Prompt struct, see <a 033 * href="https://google.github.io/dotprompt/reference/frontmatter/">Spec</a> and the (TypeScript) <a 034 * href="https://github.com/google/dotprompt/blob/main/js/src/types.ts">Reference 035 * Implementation</a>. 036 * 037 * @author <a href="http://www.vorburger.ch">Michael Vorburger.ch</a> 038 */ 039public class DotPrompt extends WithSchema { 040 041 // TODO Rethink @Nullable ... it's a mess because some fields MAY be null 042 // initially, e.g. in a YAML frontmatter, but then WONT be null after DotPromptLoader; 043 // should there be 2 different (sub?)classes - just because of that?! 044 045 // This is a class instead of a record to allow users to extend it. 046 047 // This is a trivial "struct" instead of a (*Builder) "bean", with getters and setters, 048 // because... there is really no need for that, here - this is totally fine and enough. 049 050 /** The URL of where this DotPrompt originated. */ 051 public @Nullable URI id; 052 053 /** 054 * The name of the prompt. If not specified, it will be inferred from the filename in the URL of 055 * the loaded prompt (e.g. {@code http://example.org/stuff/example.prompt.md} has an inferred 056 * name of {@code example}). 057 */ 058 public @Nullable String name; 059 060 /** 061 * The variant name for the prompt. If null, then inferred from the filename in the URL of the 062 * loaded prompt (e.g. {@code http://example.org/stuff/example.variant1.prompt.md} has an 063 * inferred name of {@code example} and inferred variant of {@code variant1}). 064 */ 065 // TODO public @Nullable String variant; 066 067 /** 068 * The name of the model to use for this prompt, based on the <a 069 * href="https://docs.enola.dev/specs/aiuri/">Enola.dev AI URI specification</a>; so e.g., 070 * {@code google://?model=gemini-2.5-flash}. May be omitted, in which case a default model will 071 * be used. 072 */ 073 public @Nullable String model; 074 075 /** 076 * Configuration to be passed to the model. The specific options may vary depending on the 077 * model. Note that version, temperature, topK, topP & maxOutputTokens are already specified as 078 * query parameters in the model AI URI instead of here. 079 */ 080 // TODO public final Map<String, Object> config = new HashMap<>(); 081 082 /** Names of registered tools to allow use of in this prompt. */ 083 public final Set<String> tools = new HashSet<>(); 084 085 /** Arbitrary metadata to be used by code, tools, and libraries. */ 086 // TODO public final Map<String, Object> metadata = new HashMap<>(); 087 088 /** Defines the (schema of the) input variables the prompt. */ 089 public @Nullable Input input; 090 091 /** Defines the expected model output format. */ 092 public @Nullable Output output; 093 094 /** 095 * Template of Prompt, as text. 096 * 097 * <p>This is typically in the body (after the YAML frontmatter) of a .prompt file. 098 */ 099 public @Nullable String prompt; 100 101 /** Template of Prompt, as Template (from parsed {@link #prompt}). */ 102 public @Nullable Template template; 103 104 // TODO How to class input Map<String, Object> extends Map<String, Object> ?! 105 public static class Input { 106 107 /** 108 * Defines the default input variable values to use if none are provided. Input values 109 * passed from the implementation should be merged into these values with a shallow merge 110 * strategy. 111 */ 112 // TODO @JsonProperty("default") // cauz "default" is a reserved keyword 113 // TODO https://github.com/google/dotprompt/issues/306 re. Map<String, Object> 114 // TODO public final Map<String, Object> defaults = new HashMap<>(); 115 116 /** 117 * Schema representing the input values for the prompt. Must correspond to a JSON Schema 118 * {@code object} type. 119 */ 120 // TODO Validate by parsing with JSON Schema parser, not (just) text to basic JSON Map 121 public final Map<String, Object> schema = new HashMap<>(); 122 123 // TODO public @Nullable URI schemaRef; 124 } 125 126 public static class Output { 127 128 public enum Format { 129 json, 130 text 131 } 132 133 /** 134 * Desired output format for this prompt. Implicitly set to JSON if the schema is specified. 135 */ 136 // TODO Remove? ADK doesn't seem to support this; it just has LlmAgent.outputSchema(Schema) 137 public Format format = Format.text; 138 139 /** 140 * Schema representing the expected output from the prompt. Must correspond to a JSON Schema 141 * {@code object} type. 142 */ 143 // TODO Validate by parsing with JSON Schema parser, not (just) text to basic JSON Map 144 public final Map<String, Object> schema = new HashMap<>(); 145 146 // TODO public @Nullable URI schemaRef; 147 148 // TODO public @Nullable String outputKey; 149 } 150}