@@ -25,8 +25,8 @@ public async Task UseChatCompletionWithPlugin(bool useChatClient)
25
25
name : "Host" ,
26
26
useChatClient : useChatClient ) ;
27
27
28
- /// Create the chat history thread to capture the agent interaction.
29
- AgentThread thread = new ChatHistoryAgentThread ( ) ;
28
+ // Create the chat history thread to capture the agent interaction.
29
+ ChatHistoryAgentThread thread = new ( ) ;
30
30
31
31
// Respond to user input, invoking functions where appropriate.
32
32
await InvokeAgentAsync ( agent , thread , "Hello" ) ;
@@ -45,13 +45,46 @@ public async Task UseChatCompletionWithPluginEnumParameter(bool useChatClient)
45
45
KernelPluginFactory . CreateFromType < WidgetFactory > ( ) ,
46
46
useChatClient : useChatClient ) ;
47
47
48
- /// Create the chat history thread to capture the agent interaction.
49
- AgentThread thread = new ChatHistoryAgentThread ( ) ;
48
+ // Create the chat history thread to capture the agent interaction.
49
+ ChatHistoryAgentThread thread = new ( ) ;
50
50
51
51
// Respond to user input, invoking functions where appropriate.
52
52
await InvokeAgentAsync ( agent , thread , "Create a beautiful red colored widget for me." ) ;
53
53
}
54
54
55
+ [ Theory ]
56
+ [ InlineData ( true ) ]
57
+ [ InlineData ( false ) ]
58
+ public async Task UseChatCompletionWithPromptFunction ( bool useChatClient )
59
+ {
60
+ // Define prompt function
61
+ KernelFunction promptFunction =
62
+ KernelFunctionFactory . CreateFromPrompt (
63
+ promptTemplate :
64
+ """
65
+ Count the number of vowels in INPUT and report as a markdown table.
66
+
67
+ INPUT:
68
+ {{$input}}
69
+ """ ,
70
+ description : "Counts the number of vowels" ) ;
71
+
72
+ // Define the agent
73
+ ChatCompletionAgent agent = CreateAgentWithPlugin (
74
+ KernelPluginFactory . CreateFromFunctions ( "AgentPlugin" , [ promptFunction ] ) ,
75
+ instructions : "You job is to only and always analyze the vowels in the user input without confirmation." ,
76
+ useChatClient : useChatClient ) ;
77
+
78
+ // Add a filter to the agent's kernel to log function invocations.
79
+ agent . Kernel . FunctionInvocationFilters . Add ( new PromptFunctionFilter ( ) ) ;
80
+
81
+ // Create the chat history thread to capture the agent interaction.
82
+ ChatHistoryAgentThread thread = new ( ) ;
83
+
84
+ // Respond to user input, invoking functions where appropriate.
85
+ await InvokeAgentAsync ( agent , thread , "Who would know naught of art must learn, act, and then take his ease." ) ;
86
+ }
87
+
55
88
[ Theory ]
56
89
[ InlineData ( true ) ]
57
90
[ InlineData ( false ) ]
@@ -72,45 +105,90 @@ public async Task UseChatCompletionWithTemplateExecutionSettings(bool useChatCli
72
105
73
106
agent . Kernel . Plugins . AddFromType < WidgetFactory > ( ) ;
74
107
75
- /// Create the chat history thread to capture the agent interaction.
76
- AgentThread thread = new ChatHistoryAgentThread ( ) ;
108
+ // Create the chat history thread to capture the agent interaction.
109
+ ChatHistoryAgentThread thread = new ( ) ;
77
110
78
111
// Respond to user input, invoking functions where appropriate.
79
112
await InvokeAgentAsync ( agent , thread , "Create a beautiful red colored widget for me." ) ;
80
113
81
114
chatClient ? . Dispose ( ) ;
82
115
}
83
116
117
+ [ Theory ]
118
+ [ InlineData ( true ) ]
119
+ [ InlineData ( false ) ]
120
+ public async Task UseChatCompletionWithManualFunctionCalling ( bool useChatClient )
121
+ {
122
+ // Define the agent
123
+ ChatCompletionAgent agent = CreateAgentWithPlugin (
124
+ KernelPluginFactory . CreateFromType < MenuPlugin > ( ) ,
125
+ functionChoiceBehavior : FunctionChoiceBehavior . Auto ( autoInvoke : false ) ,
126
+ useChatClient : useChatClient ) ;
127
+
128
+ /// Create the chat history thread to capture the agent interaction.
129
+ ChatHistoryAgentThread thread = new ( ) ;
130
+
131
+ // Respond to user input, invoking functions where appropriate.
132
+ await InvokeAgentAsync ( agent , thread , "What is the special soup and its price?" ) ;
133
+ await InvokeAgentAsync ( agent , thread , "What is the special drink and its price?" ) ;
134
+ }
135
+
84
136
private ChatCompletionAgent CreateAgentWithPlugin (
85
137
KernelPlugin plugin ,
86
138
string ? instructions = null ,
87
139
string ? name = null ,
140
+ FunctionChoiceBehavior ? functionChoiceBehavior = null ,
88
141
bool useChatClient = false )
89
142
{
90
143
ChatCompletionAgent agent =
91
- new ( )
92
- {
93
- Instructions = instructions ,
94
- Name = name ,
95
- Kernel = this . CreateKernelWithChatCompletion ( useChatClient , out _ ) ,
96
- Arguments = new KernelArguments ( new PromptExecutionSettings ( ) { FunctionChoiceBehavior = FunctionChoiceBehavior . Auto ( ) } ) ,
97
- } ;
144
+ new ( )
145
+ {
146
+ Instructions = instructions ,
147
+ Name = name ,
148
+ Kernel = this . CreateKernelWithChatCompletion ( useChatClient , out _ ) ,
149
+ Arguments = new KernelArguments ( new PromptExecutionSettings ( ) { FunctionChoiceBehavior = functionChoiceBehavior ?? FunctionChoiceBehavior . Auto ( ) } ) ,
150
+ } ;
98
151
99
152
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
100
153
agent . Kernel . Plugins . Add ( plugin ) ;
101
154
102
155
return agent ;
103
156
}
104
157
105
- // Local function to invoke agent and display the conversation messages.
106
- private async Task InvokeAgentAsync ( ChatCompletionAgent agent , AgentThread thread , string input )
158
+ private async Task InvokeAgentAsync ( ChatCompletionAgent agent , ChatHistoryAgentThread thread , string input )
107
159
{
108
160
ChatMessageContent message = new ( AuthorRole . User , input ) ;
109
161
this . WriteAgentChatMessage ( message ) ;
110
162
111
163
await foreach ( ChatMessageContent response in agent . InvokeAsync ( message , thread ) )
112
164
{
113
165
this . WriteAgentChatMessage ( response ) ;
166
+
167
+ Task < FunctionResultContent > [ ] functionResults = await ProcessFunctionCalls ( response , agent . Kernel ) . ToArrayAsync ( ) ;
168
+ thread . ChatHistory . Add ( response ) ;
169
+ foreach ( ChatMessageContent functionResult in functionResults . Select ( result => result . Result . ToChatMessage ( ) ) )
170
+ {
171
+ this . WriteAgentChatMessage ( functionResult ) ;
172
+ thread . ChatHistory . Add ( functionResult ) ;
173
+ }
174
+ }
175
+ }
176
+
177
+ private async IAsyncEnumerable < Task < FunctionResultContent > > ProcessFunctionCalls ( ChatMessageContent response , Kernel kernel )
178
+ {
179
+ foreach ( FunctionCallContent functionCall in response . Items . OfType < FunctionCallContent > ( ) )
180
+ {
181
+ yield return functionCall . InvokeAsync ( kernel ) ;
182
+ }
183
+ }
184
+
185
+ private sealed class PromptFunctionFilter : IFunctionInvocationFilter
186
+ {
187
+ public async Task OnFunctionInvocationAsync ( FunctionInvocationContext context , Func < FunctionInvocationContext , Task > next )
188
+ {
189
+ System . Console . WriteLine ( $ "INVOKING: { context . Function . Name } ") ;
190
+ await next . Invoke ( context ) ;
191
+ System . Console . WriteLine ( $ "RESULT: { context . Result } ") ;
114
192
}
115
193
}
116
194
}
0 commit comments