1+ /*
2+ * Copyright 2024-2025 Embabel Software, Inc.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package com .embabel .template .agent ;
17+
18+ import com .embabel .agent .api .annotation .AchievesGoal ;
19+ import com .embabel .agent .api .annotation .Action ;
20+ import com .embabel .agent .api .annotation .Agent ;
21+ import com .embabel .agent .api .common .OperationContext ;
22+ import com .embabel .agent .api .common .PromptRunner ;
23+ import com .embabel .agent .domain .io .UserInput ;
24+ import com .embabel .agent .domain .library .HasContent ;
25+ import com .embabel .agent .prompt .Persona ;
26+ import com .embabel .common .ai .model .AutoModelSelectionCriteria ;
27+ import com .embabel .common .ai .model .LlmOptions ;
28+ import com .embabel .common .core .types .Timestamped ;
29+ import org .springframework .beans .factory .annotation .Value ;
30+ import org .springframework .context .annotation .Profile ;
31+ import org .springframework .lang .NonNull ;
32+
33+ import java .time .Instant ;
34+ import java .time .ZoneId ;
35+ import java .time .format .DateTimeFormatter ;
36+
37+
38+ abstract class Personas {
39+ static final Persona WRITER = Persona .create (
40+ "Roald Dahl" ,
41+ "A creative storyteller who loves to weave imaginative tales that are a bit unconventional" ,
42+ "Quirky" ,
43+ "Create memorable stories that captivate the reader's imagination."
44+ );
45+ static final Persona REVIEWER = Persona .Companion .create (
46+ "Media Book Review" ,
47+ "New York Times Book Reviewer" ,
48+ "Professional and insightful" ,
49+ "Help guide readers toward good stories"
50+ );
51+ }
52+
53+ record Story (String text ) {}
54+
55+ record ReviewedStory (
56+ Story story ,
57+ String review ,
58+ Persona reviewer
59+ ) implements HasContent , Timestamped {
60+
61+ @ Override
62+ @ NonNull
63+ public Instant getTimestamp () {
64+ return Instant .now ();
65+ }
66+
67+ @ Override
68+ @ NonNull
69+ public String getContent () {
70+ return String .format ("""
71+ # Story
72+ %s
73+
74+ # Review
75+ %s
76+
77+ # Reviewer
78+ %s, %s
79+ """ ,
80+ story .text (),
81+ review ,
82+ reviewer .getName (),
83+ getTimestamp ().atZone (ZoneId .systemDefault ())
84+ .format (DateTimeFormatter .ofPattern ("EEEE, MMMM dd, yyyy" ))
85+ ).trim ();
86+ }
87+ }
88+
89+ @ Agent (description = "Generate a story based on user input and review it" )
90+ @ Profile ("!test" )
91+ class WriteAndReviewAgent {
92+
93+ private final int storyWordCount ;
94+ private final int reviewWordCount ;
95+
96+ WriteAndReviewAgent (
97+ @ Value ("${storyWordCount:100}" ) int storyWordCount ,
98+ @ Value ("${reviewWordCount:100}" ) int reviewWordCount
99+ ) {
100+ this .storyWordCount = storyWordCount ;
101+ this .reviewWordCount = reviewWordCount ;
102+ }
103+
104+ @ Action
105+ Story craftStory (UserInput userInput ) {
106+ return PromptRunner .usingLlm (
107+ LlmOptions .fromCriteria (AutoModelSelectionCriteria .INSTANCE )
108+ .withTemperature (0.9 ) // Higher temperature for more creative output
109+ ).withPromptContributor (Personas .WRITER )
110+ .createObject (String .format ("""
111+ Craft a short story in %d words or less.
112+ The story should be engaging and imaginative.
113+ Use the user's input as inspiration if possible.
114+ If the user has provided a name, include it in the story.
115+
116+ # User input
117+ %s
118+ """ ,
119+ storyWordCount ,
120+ userInput .getContent ()
121+ ).trim (), Story .class );
122+ }
123+
124+ @ AchievesGoal (description ="The user has been greeted" )
125+ @ Action
126+ ReviewedStory reviewStory (UserInput userInput , Story story , OperationContext context ) {
127+ String review = context .promptRunner ()
128+ .withLlm (LlmOptions .fromCriteria (AutoModelSelectionCriteria .INSTANCE ))
129+ .withPromptContributor (Personas .REVIEWER )
130+ .generateText (String .format ("""
131+ You will be given a short story to review.
132+ Review it in %d words or less.
133+ Consider whether or not the story is engaging, imaginative, and well-written.
134+ Also consider whether the story is appropriate given the original user input.
135+
136+ # Story
137+ %s
138+
139+ # User input that inspired the story
140+ %s
141+ """ ,
142+ reviewWordCount ,
143+ story .text (),
144+ userInput .getContent ()
145+ ).trim ());
146+
147+ return new ReviewedStory (
148+ story ,
149+ review ,
150+ Personas .REVIEWER
151+ );
152+ }
153+ }
0 commit comments