Skip to content

Commit 22270e5

Browse files
HavenDVclaude
andcommitted
feat: remove LangChain.Providers.Abstractions dependency, add MEAI DI extensions
- Move non-MEAI provider interfaces (ITextToSpeechModel, ITextToImageModel, IImageToTextModel, ISupportsCountTokens) locally into Core/src/Providers/ - Remove LangChain.Providers.Abstractions NuGet reference from Core and Serve.OpenAI - Add LangChain.Extensions.DependencyInjection project with MEAI service registration helpers (AddChatClient, AddEmbeddingGenerator, AddSpeechToTextClient) - Update tests to use ChatMessage instead of old Message type Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 369943b commit 22270e5

24 files changed

Lines changed: 572 additions & 9 deletions

CLAUDE.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ src/
4848
│ ├── Abstractions/ # LangChain.Splitters.Abstractions (CharacterTextSplitter, etc.)
4949
│ └── CSharp/ # LangChain.Splitters.CSharp
5050
├── Extensions/
51-
│ ├── DependencyInjection/ # LangChain.Extensions.DependencyInjection
5251
│ └── Docker/ # LangChain.Extensions.Docker
5352
├── Serve/
5453
│ ├── Abstractions/ # LangChain.Serve.Abstractions
@@ -59,7 +58,7 @@ src/
5958
│ ├── Sql/ # LangChain.Utilities.Sql
6059
│ └── Postgres/ # LangChain.Utilities.Postgres
6160
├── Cli/ # LangChain.Cli
62-
└── Providers/Abstractions/ # Local copy of provider abstractions (mirrors LangChain.Providers)
61+
# Note: Non-MEAI provider interfaces (TTS, Image, ImageToText) are in Core/src/Providers/
6362
examples/ # Sample projects (OpenAI, Azure, Memory, Serve, LocalRAG, etc.)
6463
```
6564

@@ -87,12 +86,12 @@ examples/ # Sample projects (OpenAI, Azure, Memory, Serve,
8786
### Dependencies
8887

8988
LangChain.Core depends on:
90-
- `LangChain.Providers.Abstractions` (NuGet) — non-MEAI provider interfaces (ITextToSpeechModel, ITextToImageModel, IImageToTextModel) and message types (Message, MessageRole)
9189
- `LangChain.Databases.Abstractions` (NuGet) — message history (BaseChatMessageHistory, ChatMessageHistory)
92-
- `Microsoft.Extensions.AI` (NuGet) — MEAI interfaces (IChatClient, IEmbeddingGenerator, ISpeechToTextClient)
90+
- `Microsoft.Extensions.AI` (NuGet) — MEAI interfaces (IChatClient, IEmbeddingGenerator, ISpeechToTextClient, ChatMessage, ChatRole)
9391
- `Microsoft.Extensions.VectorData.Abstractions` (NuGet) — MEVA vector store abstractions (`VectorStore`, `VectorStoreCollection<TKey, TRecord>`)
9492
- `LangChain.DocumentLoaders.Abstractions` (project reference)
9593
- `LangChain.Splitters.Abstractions` (project reference)
94+
- Non-MEAI provider interfaces (ITextToSpeechModel, ITextToImageModel, IImageToTextModel) are defined locally in `src/Core/src/Providers/`
9695

9796
The meta-package additionally references:
9897
- `tryAGI.OpenAI`, `tryAGI.Anthropic`, `Ollama` — SDK packages implementing MEAI interfaces natively

LangChain.slnx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
<Folder Name="/Extensions/">
2828
<File Path="src/Extensions/Directory.Build.props" />
2929
</Folder>
30+
<Folder Name="/Extensions/DependencyInjection/">
31+
<Project Path="src/Extensions/DependencyInjection/src/LangChain.Extensions.DependencyInjection.csproj" />
32+
</Folder>
3033
<Folder Name="/Extensions/Docker/">
3134
<Project Path="src/Extensions/Docker/src/LangChain.Extensions.Docker.csproj" />
3235
</Folder>

src/Core/src/LangChain.Core.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
<ItemGroup>
2929
<PackageReference Include="LangChain.Databases.Abstractions" />
30-
<PackageReference Include="LangChain.Providers.Abstractions" />
3130
<PackageReference Include="Microsoft.Extensions.AI" />
3231
<PackageReference Include="Microsoft.Extensions.VectorData.Abstractions" />
3332
</ItemGroup>

src/Core/src/Providers/Data.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Binary data wrapper with base64/byte[]/stream conversions.
5+
/// </summary>
6+
public class Data
7+
{
8+
private byte[]? _bytes;
9+
private string? _base64;
10+
11+
/// <inheritdoc cref="ToData(string)"/>
12+
public static implicit operator Data(string message)
13+
{
14+
return ToData(message);
15+
}
16+
17+
/// <summary>
18+
/// Converts a base64 string to <see cref="Data"/>.
19+
/// </summary>
20+
public static Data ToData(string base64)
21+
{
22+
return new Data
23+
{
24+
_base64 = base64,
25+
};
26+
}
27+
28+
public static Data FromStream(Stream stream)
29+
{
30+
stream = stream ?? throw new ArgumentNullException(nameof(stream));
31+
32+
using var memoryStream = new MemoryStream();
33+
stream.CopyTo(memoryStream);
34+
memoryStream.Position = 0;
35+
36+
return new Data
37+
{
38+
_bytes = memoryStream.ToArray(),
39+
};
40+
}
41+
42+
public static Data FromBytes(byte[] bytes)
43+
{
44+
return new Data
45+
{
46+
_bytes = bytes,
47+
};
48+
}
49+
50+
public static Data FromBase64(string base64)
51+
{
52+
return new Data
53+
{
54+
_base64 = base64,
55+
};
56+
}
57+
58+
public static implicit operator byte[](Data file)
59+
{
60+
return file?.ToByteArray() ?? [];
61+
}
62+
63+
public static implicit operator string(Data file)
64+
{
65+
return file?.ToBase64() ?? string.Empty;
66+
}
67+
68+
public static implicit operator Stream(Data file)
69+
{
70+
return file?.ToStream() ?? new MemoryStream();
71+
}
72+
73+
public string ToBase64()
74+
{
75+
_base64 ??= Convert.ToBase64String(_bytes ?? Array.Empty<byte>());
76+
77+
return _base64;
78+
}
79+
80+
public byte[] ToByteArray()
81+
{
82+
_bytes ??= Convert.FromBase64String(_base64 ?? string.Empty);
83+
84+
return _bytes;
85+
}
86+
87+
public MemoryStream ToStream()
88+
{
89+
return new MemoryStream(ToByteArray());
90+
}
91+
92+
public override string ToString()
93+
{
94+
return ToBase64();
95+
}
96+
}

src/Core/src/Providers/IModel.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Defines common model properties.
5+
/// </summary>
6+
public interface IModel
7+
{
8+
/// <summary>
9+
/// Id of the model.
10+
/// </summary>
11+
public string Id { get; }
12+
13+
/// <summary>
14+
/// Total usage of current model/provider.
15+
/// </summary>
16+
Usage Usage { get; }
17+
18+
void AddUsage(Usage usage);
19+
}
20+
21+
/// <summary>
22+
/// Defines a model with typed settings.
23+
/// </summary>
24+
public interface IModel<TSettings> : IModel
25+
{
26+
/// <summary>
27+
/// Defines the settings for the model.
28+
/// </summary>
29+
public TSettings? Settings { get; set; }
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Interface for models that support counting tokens.
5+
/// </summary>
6+
public interface ISupportsCountTokens
7+
{
8+
/// <summary>
9+
/// Counts the number of tokens in the given text.
10+
/// </summary>
11+
public int CountTokens(string text);
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Defines a model that can generate text from images.
5+
/// </summary>
6+
public interface IImageToTextModel : IModel<ImageToTextSettings>
7+
{
8+
/// <summary>
9+
/// Generates text from the given image.
10+
/// </summary>
11+
public Task<ImageToTextResponse> GenerateTextFromImageAsync(
12+
ImageToTextRequest request,
13+
ImageToTextSettings? settings = null,
14+
CancellationToken cancellationToken = default);
15+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Image-to-text request.
5+
/// </summary>
6+
public class ImageToTextRequest
7+
{
8+
/// <summary>
9+
/// Description/prompt for the image.
10+
/// </summary>
11+
public string Prompt { get; init; } = string.Empty;
12+
13+
/// <summary>
14+
/// Image to process.
15+
/// </summary>
16+
public required BinaryData Image { get; init; }
17+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Image-to-text response.
5+
/// </summary>
6+
public class ImageToTextResponse
7+
{
8+
/// <summary>
9+
/// The settings used for this request.
10+
/// </summary>
11+
public required ImageToTextSettings UsedSettings { get; init; }
12+
13+
/// <summary>
14+
/// Usage information.
15+
/// </summary>
16+
public Usage Usage { get; init; } = Usage.Empty;
17+
18+
/// <summary>
19+
/// Generated text.
20+
/// </summary>
21+
public string? Text { get; set; }
22+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace LangChain.Providers;
2+
3+
/// <summary>
4+
/// Image-to-text settings.
5+
/// </summary>
6+
public class ImageToTextSettings
7+
{
8+
public static ImageToTextSettings Default { get; } = new()
9+
{
10+
User = string.Empty,
11+
};
12+
13+
/// <summary>
14+
/// Unique user identifier.
15+
/// </summary>
16+
public string? User { get; init; }
17+
18+
/// <summary>
19+
/// Calculate the settings to use for the request.
20+
/// </summary>
21+
public static ImageToTextSettings Calculate(
22+
ImageToTextSettings? requestSettings,
23+
ImageToTextSettings? modelSettings,
24+
ImageToTextSettings? providerSettings)
25+
{
26+
return new ImageToTextSettings
27+
{
28+
User =
29+
requestSettings?.User ??
30+
modelSettings?.User ??
31+
providerSettings?.User ??
32+
Default.User ??
33+
throw new InvalidOperationException("Default User is not set."),
34+
};
35+
}
36+
}

0 commit comments

Comments
 (0)