Skip to content

Commit 5cc6cf1

Browse files
authored
Add Prompt Source Handler (#378)
1 parent 2c246a5 commit 5cc6cf1

File tree

51 files changed

+1628
-492
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1628
-492
lines changed

$PROFILE.txt

Whitespace-only changes.

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export COPILOT_CUSTOM_INSTRUCTIONS_DIRS=./copilot-cli

.github/workflows/deploy_docs.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
branches:
66
- main
77
tags:
8-
- 'v*.*.*'
8+
- 'v[0-9]+.[0-9]+.0'
99
workflow_dispatch:
1010

1111
permissions:
@@ -40,9 +40,13 @@ jobs:
4040
- name: Create versioned docs on tag push
4141
if: startsWith(github.ref, 'refs/tags/v')
4242
run: |
43-
VERSION="${GITHUB_REF#refs/tags/v}"
44-
echo "Creating docs version ${VERSION}"
45-
npx docusaurus docs:version "${VERSION}"
43+
FULL_VERSION="${GITHUB_REF#refs/tags/v}"
44+
# Extract major.minor for the doc version (e.g., v3.1.0 -> 3.1.x)
45+
MAJOR="$(echo "$FULL_VERSION" | cut -d. -f1)"
46+
MINOR="$(echo "$FULL_VERSION" | cut -d. -f2)"
47+
DOC_VERSION="${MAJOR}.${MINOR}.x"
48+
echo "Creating docs version ${DOC_VERSION}"
49+
npx docusaurus docs:version "${DOC_VERSION}"
4650
4751
- name: Build site
4852
run: npm run build

CrestApps.OrchardCore.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
</Folder>
1616
<Folder Name="/Core/">
1717
<Project Path="src/Core/CrestApps.Azure.Core/CrestApps.Azure.Core.csproj" />
18+
<Project Path="src/Core/CrestApps.OrchardCore.AI.Chat.Core/CrestApps.OrchardCore.AI.Chat.Core.csproj" />
1819
<Project Path="src/Core/CrestApps.OrchardCore.AI.Chat.Interactions.Core/CrestApps.OrchardCore.AI.Chat.Interactions.Core.csproj" />
1920
<Project Path="src/Core/CrestApps.OrchardCore.AI.Core/CrestApps.OrchardCore.AI.Core.csproj" />
2021
<Project Path="src/Core/CrestApps.OrchardCore.AI.Mcp.Core/CrestApps.OrchardCore.AI.Mcp.Core.csproj" />
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using CrestApps.OrchardCore.AI.Models;
2+
3+
namespace CrestApps.OrchardCore.AI;
4+
5+
/// <summary>
6+
/// Defines a pluggable handler responsible for processing chat prompts and producing responses.
7+
/// Implementations may generate responses in real time (streaming) or defer them
8+
/// for asynchronous delivery (e.g., via webhook from a third-party agent platform).
9+
/// </summary>
10+
/// <remarks>
11+
/// <para>The default implementation routes prompts through the AI orchestration pipeline.
12+
/// Custom implementations can route prompts to external systems such as live-agent
13+
/// platforms (e.g., Genesys, Twilio Flex) or any other backend capable of handling
14+
/// human-to-human or hybrid conversations.</para>
15+
///
16+
/// <para>The active handler for a session is determined by
17+
/// <see cref="AIChatSession.ResponseHandlerName"/> or
18+
/// <see cref="ChatInteraction.ResponseHandlerName"/>. An AI function or external
19+
/// event can change this value mid-conversation to transfer the chat to a different handler.</para>
20+
/// </remarks>
21+
public interface IChatResponseHandler
22+
{
23+
/// <summary>
24+
/// Gets the unique technical name of this handler (e.g., <c>"AI"</c>, <c>"Genesys"</c>).
25+
/// </summary>
26+
string Name { get; }
27+
28+
/// <summary>
29+
/// Processes a chat prompt and returns a result indicating whether the response
30+
/// is available immediately (streaming) or will be delivered later (deferred).
31+
/// </summary>
32+
/// <param name="context">The context describing the prompt, session, and connection details.</param>
33+
/// <param name="cancellationToken">A token to cancel the operation.</param>
34+
/// <returns>
35+
/// A <see cref="ChatResponseHandlerResult"/> that is either streaming (contains an
36+
/// <see cref="IAsyncEnumerable{T}"/> of updates) or deferred (the hub will not wait
37+
/// for a response).
38+
/// </returns>
39+
Task<ChatResponseHandlerResult> HandleAsync(
40+
ChatResponseHandlerContext context,
41+
CancellationToken cancellationToken = default);
42+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using CrestApps.OrchardCore.AI.Models;
2+
3+
namespace CrestApps.OrchardCore.AI;
4+
5+
/// <summary>
6+
/// Resolves the appropriate <see cref="IChatResponseHandler"/> for a chat session based
7+
/// on the configured handler name.
8+
/// </summary>
9+
/// <remarks>
10+
/// Resolution order: explicit name → default AI handler.
11+
/// When <paramref name="handlerName"/> is <see langword="null"/> or empty, the built-in AI
12+
/// handler is returned. When a name is specified but no matching handler is found,
13+
/// implementations should fall back to the default AI handler.
14+
/// When <paramref name="chatMode"/> is <see cref="ChatMode.Conversation"/>,
15+
/// the AI handler is always returned regardless of the requested name because
16+
/// conversation mode requires the AI orchestration pipeline for speech-to-text
17+
/// and text-to-speech integration.
18+
/// </remarks>
19+
public interface IChatResponseHandlerResolver
20+
{
21+
/// <summary>
22+
/// Resolves a chat response handler by name.
23+
/// </summary>
24+
/// <param name="handlerName">
25+
/// The handler name, or <see langword="null"/> / empty for the default AI handler.
26+
/// </param>
27+
/// <param name="chatMode">
28+
/// The active chat mode. When set to <see cref="ChatMode.Conversation"/>, the
29+
/// built-in AI handler is always returned regardless of <paramref name="handlerName"/>.
30+
/// </param>
31+
/// <returns>The resolved <see cref="IChatResponseHandler"/> instance.</returns>
32+
IChatResponseHandler Resolve(string handlerName = null, ChatMode chatMode = ChatMode.TextInput);
33+
34+
/// <summary>
35+
/// Gets all registered <see cref="IChatResponseHandler"/> instances.
36+
/// </summary>
37+
/// <returns>An enumerable of all registered handlers.</returns>
38+
IEnumerable<IChatResponseHandler> GetAll();
39+
}

src/Abstractions/CrestApps.OrchardCore.AI.Abstractions/Models/AIChatSession.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public sealed class AIChatSession : Entity
6161
/// </summary>
6262
public ChatSessionStatus Status { get; set; }
6363

64+
/// <summary>
65+
/// Gets or sets the technical name of the <see cref="IChatResponseHandler"/> currently
66+
/// handling prompts for this session. When <see langword="null"/> or empty, the default
67+
/// AI handler is used. This value can be changed mid-conversation (e.g., by an AI
68+
/// function that transfers the chat to a live-agent platform).
69+
/// </summary>
70+
public string ResponseHandlerName { get; set; }
71+
6472
/// <summary>
6573
/// Gets or sets the extracted data fields for this session.
6674
/// Keys are field names from the data extraction configuration.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace CrestApps.OrchardCore.AI.Models;
2+
3+
/// <summary>
4+
/// Identifies the type of chat context a <see cref="ChatResponseHandlerContext"/> represents.
5+
/// </summary>
6+
public enum ChatContextType
7+
{
8+
/// <summary>
9+
/// The context is for an <see cref="AIChatSession"/> managed by the AI Chat module.
10+
/// </summary>
11+
AIChatSession,
12+
13+
/// <summary>
14+
/// The context is for a <see cref="ChatInteraction"/> managed by the Chat Interactions module.
15+
/// </summary>
16+
ChatInteraction,
17+
}

src/Abstractions/CrestApps.OrchardCore.AI.Abstractions/Models/ChatInteraction.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ private string _deploymentIdBackingField
107107
/// </summary>
108108
public string OrchestratorName { get; set; }
109109

110+
/// <summary>
111+
/// Gets or sets the technical name of the <see cref="IChatResponseHandler"/> currently
112+
/// handling prompts for this interaction. When <see langword="null"/> or empty, the default
113+
/// AI handler is used. This value can be changed mid-conversation (e.g., by an AI
114+
/// function that transfers the chat to a live-agent platform).
115+
/// </summary>
116+
public string ResponseHandlerName { get; set; }
117+
110118
/// <summary>
111119
/// Gets or sets the list of AI tool names to use.
112120
/// </summary>

0 commit comments

Comments
 (0)