11
11
from pydantic .fields import FieldInfo
12
12
13
13
from dspy .adapters .base import Adapter
14
+ from dspy .adapters .types .history import History
14
15
from dspy .adapters .utils import format_field_value , get_annotation_name , parse_value
15
16
from dspy .signatures .field import OutputField
16
17
from dspy .signatures .signature import Signature , SignatureMeta
@@ -46,15 +47,23 @@ def format(self, signature: Signature, demos: list[dict[str, Any]], inputs: dict
46
47
]
47
48
48
49
demos = incomplete_demos + complete_demos
49
-
50
50
prepared_instructions = prepare_instructions (signature )
51
51
messages .append ({"role" : "system" , "content" : prepared_instructions })
52
+
53
+ # Add the few-shot examples
52
54
for demo in demos :
53
- messages .append (format_turn (signature , demo , role = "user" , incomplete = demo in incomplete_demos ))
54
- messages .append (format_turn (signature , demo , role = "assistant" , incomplete = demo in incomplete_demos ))
55
+ messages .append (self .format_turn (signature , demo , role = "user" , incomplete = demo in incomplete_demos ))
56
+ messages .append (self .format_turn (signature , demo , role = "assistant" , incomplete = demo in incomplete_demos ))
57
+
58
+ # Add the chat history after few-shot examples
59
+ if any (field .annotation == History for field in signature .input_fields .values ()):
60
+ messages .extend (self .format_conversation_history (signature , inputs ))
61
+ else :
62
+ messages .append (self .format_turn (signature , inputs , role = "user" ))
55
63
56
64
messages .append (format_turn (signature , inputs , role = "user" ))
57
65
messages = try_expand_media_tags (messages )
66
+
58
67
return messages
59
68
60
69
def parse (self , signature , completion ):
@@ -92,7 +101,7 @@ def format_finetune_data(self, signature, demos, inputs, outputs):
92
101
# Add the assistant message
93
102
role = "assistant"
94
103
incomplete = False
95
- assistant_message = format_turn (signature , outputs , role , incomplete )
104
+ assistant_message = self . format_turn (signature , outputs , role , incomplete )
96
105
messages .append (assistant_message )
97
106
98
107
# Wrap the messages in a dictionary with a "messages" key
@@ -108,6 +117,9 @@ def format_fields(self, signature, values, role):
108
117
}
109
118
return format_fields (fields_with_values )
110
119
120
+ def format_turn (self , signature , values , role , incomplete = False , is_conversation_history = False ):
121
+ return format_turn (signature , values , role , incomplete , is_conversation_history )
122
+
111
123
112
124
def format_fields (fields_with_values : Dict [FieldInfoWithName , Any ]) -> str :
113
125
"""
@@ -129,7 +141,7 @@ def format_fields(fields_with_values: Dict[FieldInfoWithName, Any]) -> str:
129
141
return "\n \n " .join (output ).strip ()
130
142
131
143
132
- def format_turn (signature , values , role , incomplete = False ):
144
+ def format_turn (signature , values , role , incomplete = False , is_conversation_history = False ):
133
145
"""
134
146
Constructs a new message ("turn") to append to a chat thread. The message is carefully formatted
135
147
so that it can instruct an LLM to generate responses conforming to the specified DSPy signature.
@@ -140,24 +152,31 @@ def format_turn(signature, values, role, incomplete=False):
140
152
that should be included in the message.
141
153
role: The role of the message, which can be either "user" or "assistant".
142
154
incomplete: If True, indicates that output field values are present in the set of specified
143
- ``values``. If False, indicates that ``values`` only contains input field values.
155
+ `values`. If False, indicates that `values` only contains input field values. Only used if
156
+ `is_conversation_history` is False.
157
+ is_conversation_history: If True, indicates that the message is part of the chat history, otherwise
158
+ it is a demo (few-shot example).
144
159
145
160
Returns:
146
161
A chat message that can be appended to a chat thread. The message contains two string fields:
147
- `` role`` ("user" or "assistant") and `` content` ` (the message text).
162
+ `role` ("user" or "assistant") and `content` (the message text).
148
163
"""
149
164
if role == "user" :
150
165
fields = signature .input_fields
151
- message_prefix = (
152
- "This is an example of the task, though some input or output fields are not supplied." if incomplete else ""
153
- )
166
+ if incomplete and not is_conversation_history :
167
+ message_prefix = "This is an example of the task, though some input or output fields are not supplied."
168
+ else :
169
+ message_prefix = ""
154
170
else :
155
- # Add the completed field for the assistant turn
156
- fields = {** signature .output_fields , BuiltInCompletedOutputFieldInfo . name : BuiltInCompletedOutputFieldInfo . info }
157
- values = {** values , BuiltInCompletedOutputFieldInfo . name : "" }
171
+ # Add the completed field or chat history for the assistant turn
172
+ fields = {** signature .output_fields }
173
+ values = {** values }
158
174
message_prefix = ""
175
+ if not is_conversation_history :
176
+ fields .update ({BuiltInCompletedOutputFieldInfo .name : BuiltInCompletedOutputFieldInfo .info })
177
+ values .update ({BuiltInCompletedOutputFieldInfo .name : "" })
159
178
160
- if not incomplete and not set (values ).issuperset (fields .keys ()):
179
+ if not incomplete and not is_conversation_history and not set (values ).issuperset (fields .keys ()):
161
180
raise ValueError (f"Expected { fields .keys ()} but got { values .keys ()} " )
162
181
163
182
messages = []
@@ -166,7 +185,12 @@ def format_turn(signature, values, role, incomplete=False):
166
185
167
186
field_messages = format_fields (
168
187
{
169
- FieldInfoWithName (name = k , info = v ): values .get (k , "Not supplied for this particular example." )
188
+ FieldInfoWithName (name = k , info = v ): values .get (
189
+ k ,
190
+ "Not supplied for this conversation history message. "
191
+ if is_conversation_history
192
+ else "Not supplied for this particular example. " ,
193
+ )
170
194
for k , v in fields .items ()
171
195
},
172
196
)
0 commit comments