-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClaudeChatClient.cs
More file actions
98 lines (81 loc) · 3.32 KB
/
ClaudeChatClient.cs
File metadata and controls
98 lines (81 loc) · 3.32 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
using System.Runtime.CompilerServices;
using ManagedCode.ClaudeCodeSharpSDK.Client;
using ManagedCode.ClaudeCodeSharpSDK.Extensions.AI.Internal;
using Microsoft.Extensions.AI;
namespace ManagedCode.ClaudeCodeSharpSDK.Extensions.AI;
public sealed class ClaudeChatClient : IChatClient
{
private const string ProviderName = "ClaudeCodeCLI";
private readonly ClaudeClient _client;
private readonly ClaudeChatClientOptions _options;
public ClaudeChatClient(ClaudeChatClientOptions? options = null)
{
_options = options ?? new ClaudeChatClientOptions();
_client = new ClaudeClient(new ClaudeClientOptions
{
ClaudeOptions = _options.ClaudeOptions,
AutoStart = true,
});
}
public async Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(messages);
var prompt = ChatMessageMapper.ToClaudeInput(messages);
var threadOptions = ChatOptionsMapper.ToThreadOptions(options, _options);
var turnOptions = ChatOptionsMapper.ToTurnOptions(options, cancellationToken);
var thread = options?.ConversationId is { } threadId
? _client.ResumeThread(threadId, threadOptions)
: _client.StartThread(threadOptions);
using (thread)
{
var result = await thread.RunAsync(prompt, turnOptions).ConfigureAwait(false);
return ChatResponseMapper.ToChatResponse(result, thread.Id);
}
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(messages);
var prompt = ChatMessageMapper.ToClaudeInput(messages);
var threadOptions = ChatOptionsMapper.ToThreadOptions(options, _options);
var turnOptions = ChatOptionsMapper.ToTurnOptions(options, cancellationToken);
var thread = options?.ConversationId is { } threadId
? _client.ResumeThread(threadId, threadOptions)
: _client.StartThread(threadOptions);
using (thread)
{
var streamed = await thread.RunStreamedAsync(prompt, turnOptions).ConfigureAwait(false);
await foreach (var update in StreamingEventMapper.ToUpdates(streamed.Events, cancellationToken)
.WithCancellation(cancellationToken)
.ConfigureAwait(false))
{
yield return update;
}
}
}
public object? GetService(Type serviceType, object? serviceKey = null)
{
if (serviceKey is not null)
{
return null;
}
if (serviceType == typeof(ChatClientMetadata))
{
return new ChatClientMetadata(
providerName: ProviderName,
providerUri: null,
defaultModelId: _options.DefaultModel ?? _options.DefaultThreadOptions?.Model);
}
if (serviceType.IsInstanceOfType(this))
{
return this;
}
return null;
}
public void Dispose() => _client.Dispose();
}