-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathAIContextProvider.cs
More file actions
511 lines (474 loc) · 30 KB
/
AIContextProvider.cs
File metadata and controls
511 lines (474 loc) · 30 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
/// <summary>
/// Provides an abstract base class for components that enhance AI context during agent invocations.
/// </summary>
/// <remarks>
/// <para>
/// An AI context provider is a component that participates in the agent invocation lifecycle by:
/// <list type="bullet">
/// <item><description>Listening to changes in conversations</description></item>
/// <item><description>Providing additional context to agents during invocation</description></item>
/// <item><description>Supplying additional function tools for enhanced capabilities</description></item>
/// <item><description>Processing invocation results for state management or learning</description></item>
/// </list>
/// </para>
/// <para>
/// Context providers operate through a two-phase lifecycle: they are called at the start of invocation via
/// <see cref="InvokingAsync"/> to provide context, and optionally called at the end of invocation via
/// <see cref="InvokedAsync"/> to process results.
/// </para>
/// <para>
/// <strong>Security considerations:</strong> Context providers may inject messages with any role, including <c>system</c>, which
/// has the highest trust level and directly shapes LLM behavior. Developers must ensure that all providers attached to an agent
/// are trusted. Agent Framework does not validate or filter the data returned by providers — it is accepted as-is and merged into
/// the request context. If a provider retrieves data from an external source (e.g., a vector database or memory service), be aware
/// that a compromised data source could introduce adversarial content designed to manipulate LLM behavior via indirect prompt injection.
/// Implementers should validate and sanitize data retrieved from external sources before returning it.
/// </para>
/// </remarks>
public abstract class AIContextProvider
{
private static IEnumerable<ChatMessage> DefaultExternalOnlyFilter(IEnumerable<ChatMessage> messages)
=> messages.Where(m => m.GetAgentRequestMessageSourceType() == AgentRequestMessageSourceType.External);
private static IEnumerable<ChatMessage> DefaultNoopFilter(IEnumerable<ChatMessage> messages)
=> messages;
private IReadOnlyList<string>? _stateKeys;
/// <summary>
/// Initializes a new instance of the <see cref="AIContextProvider"/> class.
/// </summary>
/// <param name="provideInputMessageFilter">An optional filter function to apply to input messages before providing context via <see cref="ProvideAIContextAsync"/>. If not set, defaults to including only <see cref="AgentRequestMessageSourceType.External"/> messages.</param>
/// <param name="storeInputRequestMessageFilter">An optional filter function to apply to request messages before storing context via <see cref="StoreAIContextAsync"/>. If not set, defaults to including only <see cref="AgentRequestMessageSourceType.External"/> messages.</param>
/// <param name="storeInputResponseMessageFilter">An optional filter function to apply to response messages before storing context via <see cref="StoreAIContextAsync"/>. If not set, defaults to a no-op filter that includes all response messages.</param>
protected AIContextProvider(
Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>? provideInputMessageFilter = null,
Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>? storeInputRequestMessageFilter = null,
Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>? storeInputResponseMessageFilter = null)
{
this.ProvideInputMessageFilter = provideInputMessageFilter ?? DefaultExternalOnlyFilter;
this.StoreInputRequestMessageFilter = storeInputRequestMessageFilter ?? DefaultExternalOnlyFilter;
this.StoreInputResponseMessageFilter = storeInputResponseMessageFilter ?? DefaultNoopFilter;
}
/// <summary>
/// Gets the filter function to apply to input messages before providing context via <see cref="ProvideAIContextAsync"/>.
/// </summary>
protected Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>> ProvideInputMessageFilter { get; }
/// <summary>
/// Gets the filter function to apply to request messages before storing context via <see cref="StoreAIContextAsync"/>.
/// </summary>
protected Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>> StoreInputRequestMessageFilter { get; }
/// <summary>
/// Gets the filter function to apply to response messages before storing context via <see cref="StoreAIContextAsync"/>.
/// </summary>
protected Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>> StoreInputResponseMessageFilter { get; }
/// <summary>
/// Gets the set of keys used to store the provider state in the <see cref="AgentSession.StateBag"/>.
/// </summary>
/// <remarks>
/// The default value is a single-element set containing the name of the concrete type (e.g. <c>"TextSearchProvider"</c>).
/// Implementations may override this to provide custom keys, for example when multiple
/// instances of the same provider type are used in the same session, or when a provider
/// stores state under more than one key.
/// </remarks>
public virtual IReadOnlyList<string> StateKeys => this._stateKeys ??= [this.GetType().Name];
/// <summary>
/// Called at the start of agent invocation to provide additional context.
/// </summary>
/// <param name="context">Contains the request context including the caller provided messages that will be used by the agent for this invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="AIContext"/> with additional context to be used by the agent during this invocation.</returns>
/// <remarks>
/// <para>
/// Implementers can load any additional context required at this time, such as:
/// <list type="bullet">
/// <item><description>Retrieving relevant information from knowledge bases</description></item>
/// <item><description>Adding system instructions or prompts</description></item>
/// <item><description>Providing function tools for the current invocation</description></item>
/// <item><description>Injecting contextual messages from conversation history</description></item>
/// </list>
/// </para>
/// <para>
/// <strong>Security consideration:</strong> Data retrieved from external sources (e.g., vector databases, memory services, or
/// knowledge bases) may contain adversarial content designed to influence LLM behavior via indirect prompt injection.
/// Implementers should validate data integrity and consider the trustworthiness of the data source.
/// </para>
/// </remarks>
public ValueTask<AIContext> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
=> this.InvokingCoreAsync(Throw.IfNull(context), cancellationToken);
/// <summary>
/// Called at the start of agent invocation to provide additional context.
/// </summary>
/// <param name="context">Contains the request context including the caller provided messages that will be used by the agent for this invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="AIContext"/> with additional context to be used by the agent during this invocation.</returns>
/// <remarks>
/// <para>
/// Implementers can load any additional context required at this time, such as:
/// <list type="bullet">
/// <item><description>Retrieving relevant information from knowledge bases</description></item>
/// <item><description>Adding system instructions or prompts</description></item>
/// <item><description>Providing function tools for the current invocation</description></item>
/// <item><description>Injecting contextual messages from conversation history</description></item>
/// </list>
/// </para>
/// <para>
/// The default implementation of this method filters the input messages using the configured provide-input message filter
/// (which defaults to including only <see cref="AgentRequestMessageSourceType.External"/> messages),
/// then calls <see cref="ProvideAIContextAsync"/> to get additional context,
/// stamps any messages from the returned context with <see cref="AgentRequestMessageSourceType.AIContextProvider"/> source attribution,
/// and merges the returned context with the original (unfiltered) input context (concatenating instructions, messages, and tools).
/// For most scenarios, overriding <see cref="ProvideAIContextAsync"/> is sufficient to provide additional context,
/// while still benefiting from the default filtering, merging and source stamping behavior.
/// However, for scenarios that require more control over context filtering, merging or source stamping, overriding this method
/// allows you to directly control the full <see cref="AIContext"/> returned for the invocation.
/// </para>
/// </remarks>
protected virtual async ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var inputContext = context.AIContext;
// Create a filtered context for ProvideAIContextAsync, filtering input messages
// to exclude non-external messages (e.g. chat history, other AI context provider messages).
#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var filteredContext = new InvokingContext(
context.Agent,
context.Session,
new AIContext
{
Instructions = inputContext.Instructions,
Messages = inputContext.Messages is not null ? this.ProvideInputMessageFilter(inputContext.Messages) : null,
Tools = inputContext.Tools
});
#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var provided = await this.ProvideAIContextAsync(filteredContext, cancellationToken).ConfigureAwait(false);
var mergedInstructions = (inputContext.Instructions, provided.Instructions) switch
{
(null, null) => null,
(string a, null) => a,
(null, string b) => b,
(string a, string b) => a + "\n" + b
};
var providedMessages = provided.Messages is not null
? provided.Messages.Select(m => m.WithAgentRequestMessageSource(AgentRequestMessageSourceType.AIContextProvider, this.GetType().FullName!))
: null;
var mergedMessages = (inputContext.Messages, providedMessages) switch
{
(null, null) => null,
(var a, null) => a,
(null, var b) => b,
(var a, var b) => a.Concat(b)
};
var mergedTools = (inputContext.Tools, provided.Tools) switch
{
(null, null) => null,
(var a, null) => a,
(null, var b) => b,
(var a, var b) => a.Concat(b)
};
return new AIContext
{
Instructions = mergedInstructions,
Messages = mergedMessages,
Tools = mergedTools
};
}
/// <summary>
/// When overridden in a derived class, provides additional AI context to be merged with the input context for the current invocation.
/// </summary>
/// <remarks>
/// <para>
/// This method is called from <see cref="InvokingCoreAsync"/>.
/// Note that <see cref="InvokingCoreAsync"/> can be overridden to directly control context merging and source stamping, in which case
/// it is up to the implementer to call this method as needed to retrieve the additional context.
/// </para>
/// <para>
/// In contrast with <see cref="InvokingCoreAsync"/>, this method only returns additional context to be merged with the input,
/// while <see cref="InvokingCoreAsync"/> is responsible for returning the full merged <see cref="AIContext"/> for the invocation.
/// </para>
/// <para>
/// <strong>Security consideration:</strong> Any messages, tools, or instructions returned by this method will be merged into the
/// AI request context. If data is retrieved from external or untrusted sources, implementers should validate and sanitize it
/// to prevent indirect prompt injection attacks.
/// </para>
/// </remarks>
/// <param name="context">Contains the request context including the caller provided messages that will be used by the agent for this invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains an <see cref="AIContext"/>
/// with additional context to be merged with the input context.
/// </returns>
protected virtual ValueTask<AIContext> ProvideAIContextAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
return new ValueTask<AIContext>(new AIContext());
}
/// <summary>
/// Called at the end of the agent invocation to process the invocation results.
/// </summary>
/// <param name="context">Contains the invocation context including request messages, response messages, and any exception that occurred.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// Implementers can use the request and response messages in the provided <paramref name="context"/> to:
/// <list type="bullet">
/// <item><description>Update state based on conversation outcomes</description></item>
/// <item><description>Extract and store memories or preferences from user messages</description></item>
/// <item><description>Log or audit conversation details</description></item>
/// <item><description>Perform cleanup or finalization tasks</description></item>
/// </list>
/// </para>
/// <para>
/// The <see cref="AIContextProvider"/> is passed a reference to the <see cref="AgentSession"/> via <see cref="InvokingContext"/> and <see cref="InvokedContext"/>
/// allowing it to store state in the <see cref="AgentSession.StateBag"/>. Since an <see cref="AIContextProvider"/> is used with many different sessions, it should
/// not store any session-specific information within its own instance fields. Instead, any session-specific state should be stored in the associated <see cref="AgentSession.StateBag"/>.
/// </para>
/// <para>
/// This method is called regardless of whether the invocation succeeded or failed.
/// To check if the invocation was successful, inspect the <see cref="InvokedContext.InvokeException"/> property.
/// </para>
/// </remarks>
public ValueTask InvokedAsync(InvokedContext context, CancellationToken cancellationToken = default)
=> this.InvokedCoreAsync(Throw.IfNull(context), cancellationToken);
/// <summary>
/// Called at the end of the agent invocation to process the invocation results.
/// </summary>
/// <param name="context">Contains the invocation context including request messages, response messages, and any exception that occurred.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// Implementers can use the request and response messages in the provided <paramref name="context"/> to:
/// <list type="bullet">
/// <item><description>Update internal state based on conversation outcomes</description></item>
/// <item><description>Extract and store memories or preferences from user messages</description></item>
/// <item><description>Log or audit conversation details</description></item>
/// <item><description>Perform cleanup or finalization tasks</description></item>
/// </list>
/// </para>
/// <para>
/// This method is called regardless of whether the invocation succeeded or failed.
/// To check if the invocation was successful, inspect the <see cref="InvokedContext.InvokeException"/> property.
/// </para>
/// <para>
/// The default implementation of this method skips execution for any invocation failures,
/// filters the request messages using the configured store-input request message filter
/// (which defaults to including only <see cref="AgentRequestMessageSourceType.External"/> messages),
/// filters the response messages using the configured store-input response message filter
/// (which defaults to a no-op, so all response messages are processed),
/// and calls <see cref="StoreAIContextAsync"/> to process the invocation results.
/// For most scenarios, overriding <see cref="StoreAIContextAsync"/> is sufficient to process invocation results,
/// while still benefiting from the default error handling and filtering behavior.
/// However, for scenarios that require more control over error handling or message filtering, overriding this method
/// allows you to directly control the processing of invocation results.
/// </para>
/// </remarks>
protected virtual ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
if (context.InvokeException is not null)
{
return default;
}
#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var subContext = new InvokedContext(context.Agent, context.Session, this.StoreInputRequestMessageFilter(context.RequestMessages), this.StoreInputResponseMessageFilter(context.ResponseMessages!));
#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
return this.StoreAIContextAsync(subContext, cancellationToken);
}
/// <summary>
/// When overridden in a derived class, processes invocation results at the end of the agent invocation.
/// </summary>
/// <param name="context">Contains the invocation context including request messages, response messages, and any exception that occurred.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// This method is called from <see cref="InvokedCoreAsync"/>.
/// Note that <see cref="InvokedCoreAsync"/> can be overridden to directly control error handling, in which case
/// it is up to the implementer to call this method as needed to process the invocation results.
/// </para>
/// <para>
/// In contrast with <see cref="InvokedCoreAsync"/>, this method only processes the invocation results,
/// while <see cref="InvokedCoreAsync"/> is also responsible for error handling.
/// </para>
/// <para>
/// The default implementation of <see cref="InvokedCoreAsync"/> only calls this method if the invocation succeeded.
/// </para>
/// <para>
/// <strong>Security consideration:</strong> Messages being processed/stored may contain PII and sensitive conversation content.
/// Implementers should ensure appropriate encryption at rest and access controls for the storage backend.
/// </para>
/// </remarks>
protected virtual ValueTask StoreAIContextAsync(InvokedContext context, CancellationToken cancellationToken = default) =>
default;
/// <summary>Asks the <see cref="AIContextProvider"/> for an object of the specified type <paramref name="serviceType"/>.</summary>
/// <param name="serviceType">The type of object being requested.</param>
/// <param name="serviceKey">An optional key that can be used to help identify the target service.</param>
/// <returns>The found object, otherwise <see langword="null"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="serviceType"/> is <see langword="null"/>.</exception>
/// <remarks>
/// The purpose of this method is to allow for the retrieval of strongly-typed services that might be provided by the <see cref="AIContextProvider"/>,
/// including itself or any services it might be wrapping. This enables advanced scenarios where consumers need access to
/// specific provider implementations or their internal services.
/// </remarks>
public virtual object? GetService(Type serviceType, object? serviceKey = null)
{
_ = Throw.IfNull(serviceType);
return serviceKey is null && serviceType.IsInstanceOfType(this)
? this
: null;
}
/// <summary>Asks the <see cref="AIContextProvider"/> for an object of type <typeparamref name="TService"/>.</summary>
/// <typeparam name="TService">The type of the object to be retrieved.</typeparam>
/// <param name="serviceKey">An optional key that can be used to help identify the target service.</param>
/// <returns>The found object, otherwise <see langword="null"/>.</returns>
/// <remarks>
/// The purpose of this method is to allow for the retrieval of strongly typed services that may be provided by the <see cref="AIContextProvider"/>,
/// including itself or any services it might be wrapping. This is a convenience overload of <see cref="GetService(Type, object?)"/>.
/// </remarks>
public TService? GetService<TService>(object? serviceKey = null)
=> this.GetService(typeof(TService), serviceKey) is TService service ? service : default;
/// <summary>
/// Contains the context information provided to <see cref="InvokingCoreAsync(InvokingContext, CancellationToken)"/>.
/// </summary>
/// <remarks>
/// This class provides context about the invocation before the underlying AI model is invoked, including the messages
/// that will be used. Context providers can use this information to determine what additional context
/// should be provided for the invocation.
/// </remarks>
public sealed class InvokingContext
{
/// <summary>
/// Initializes a new instance of the <see cref="InvokingContext"/> class.
/// </summary>
/// <param name="agent">The agent being invoked.</param>
/// <param name="session">The session associated with the agent invocation.</param>
/// <param name="aiContext">The AI context to be used by the agent for this invocation.</param>
/// <exception cref="ArgumentNullException"><paramref name="agent"/> or <paramref name="aiContext"/> is <see langword="null"/>.</exception>
[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokingContext(
AIAgent agent,
AgentSession? session,
AIContext aiContext)
{
this.Agent = Throw.IfNull(agent);
this.Session = session;
this.AIContext = Throw.IfNull(aiContext);
}
/// <summary>
/// Gets the agent that is being invoked.
/// </summary>
public AIAgent Agent { get; }
/// <summary>
/// Gets the agent session associated with the agent invocation.
/// </summary>
public AgentSession? Session { get; }
/// <summary>
/// Gets the <see cref="AIContext"/> being built for the current invocation. Context providers can modify
/// and return or return a new <see cref="AIContext"/> instance to provide additional context for the invocation.
/// </summary>
/// <remarks>
/// <para>
/// If multiple <see cref="AIContextProvider"/> instances are used in the same invocation, each <see cref="AIContextProvider"/>
/// will receive the context returned by the previous <see cref="AIContextProvider"/> allowing them to build on top of each other's context.
/// </para>
/// <para>
/// The first <see cref="AIContextProvider"/> in the invocation pipeline will receive an <see cref="AIContext"/> instance
/// that already contains the caller provided messages that will be used by the agent for this invocation.
/// </para>
/// <para>
/// It may also contain messages from chat history, if a <see cref="ChatHistoryProvider"/> is being used.
/// </para>
/// </remarks>
public AIContext AIContext { get; }
}
/// <summary>
/// Contains the context information provided to <see cref="InvokedCoreAsync(InvokedContext, CancellationToken)"/>.
/// </summary>
/// <remarks>
/// This class provides context about a completed agent invocation, including the accumulated
/// request messages (user input, chat history and any others provided by AI context providers) that were used
/// and the response messages that were generated. It also indicates whether the invocation succeeded or failed.
/// </remarks>
public sealed class InvokedContext
{
/// <summary>
/// Initializes a new instance of the <see cref="InvokedContext"/> class for a successful invocation.
/// </summary>
/// <param name="agent">The agent that was invoked.</param>
/// <param name="session">The session associated with the agent invocation.</param>
/// <param name="requestMessages">The accumulated request messages (user input, chat history and any others provided by AI context providers)
/// that were used by the agent for this invocation.</param>
/// <param name="responseMessages">The response messages generated during this invocation.</param>
/// <exception cref="ArgumentNullException"><paramref name="agent"/>, <paramref name="requestMessages"/>, or <paramref name="responseMessages"/> is <see langword="null"/>.</exception>
[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokedContext(
AIAgent agent,
AgentSession? session,
IEnumerable<ChatMessage> requestMessages,
IEnumerable<ChatMessage> responseMessages)
{
this.Agent = Throw.IfNull(agent);
this.Session = session;
this.RequestMessages = Throw.IfNull(requestMessages);
this.ResponseMessages = Throw.IfNull(responseMessages);
}
/// <summary>
/// Initializes a new instance of the <see cref="InvokedContext"/> class for a failed invocation.
/// </summary>
/// <param name="agent">The agent that was invoked.</param>
/// <param name="session">The session associated with the agent invocation.</param>
/// <param name="requestMessages">The accumulated request messages (user input, chat history and any others provided by AI context providers)
/// that were used by the agent for this invocation.</param>
/// <param name="invokeException">The exception that caused the invocation to fail.</param>
/// <exception cref="ArgumentNullException"><paramref name="agent"/>, <paramref name="requestMessages"/>, or <paramref name="invokeException"/> is <see langword="null"/>.</exception>
public InvokedContext(
AIAgent agent,
AgentSession? session,
IEnumerable<ChatMessage> requestMessages,
Exception invokeException)
{
this.Agent = Throw.IfNull(agent);
this.Session = session;
this.RequestMessages = Throw.IfNull(requestMessages);
this.InvokeException = Throw.IfNull(invokeException);
}
/// <summary>
/// Gets the agent that is being invoked.
/// </summary>
public AIAgent Agent { get; }
/// <summary>
/// Gets the agent session associated with the agent invocation.
/// </summary>
public AgentSession? Session { get; }
/// <summary>
/// Gets the accumulated request messages (user input, chat history and any others provided by AI context providers)
/// that were used by the agent for this invocation.
/// </summary>
/// <value>
/// A collection of <see cref="ChatMessage"/> instances representing all messages that were used by the agent for this invocation.
/// </value>
public IEnumerable<ChatMessage> RequestMessages { get; }
/// <summary>
/// Gets the collection of response messages generated during this invocation if the invocation succeeded.
/// </summary>
/// <value>
/// A collection of <see cref="ChatMessage"/> instances representing the response,
/// or <see langword="null"/> if the invocation failed.
/// </value>
public IEnumerable<ChatMessage>? ResponseMessages { get; }
/// <summary>
/// Gets the <see cref="Exception"/> that was thrown during the invocation, if the invocation failed.
/// </summary>
/// <value>
/// The exception that caused the invocation to fail, or <see langword="null"/> if the invocation succeeded.
/// </value>
public Exception? InvokeException { get; }
}
}