# CompleteAsync and CompleteStreamingAsync Not Found in Microsoft.Extensions.AI: Causes and Fixes

You follow a Microsoft.Extensions.AI tutorial, paste in the code, hit build, and the compiler stops you cold:

```plaintext
CS1061: 'IChatClient' does not contain a definition for 'CompleteAsync' and no
accessible extension method 'CompleteAsync' accepting a first argument of type
'IChatClient' could be found
```

Nothing is wrong with your code. The method was renamed. If you are searching for why `CompleteAsync` is not found in Microsoft.Extensions.AI, the short answer is that `CompleteAsync` and `CompleteStreamingAsync` were renamed to `GetResponseAsync` and `GetStreamingResponseAsync` back in the `9.3.0-preview.1.25114.11` release, and most of the blog posts and videos still on page one of Google were written before that. In production I have watched this exact error eat an afternoon on two different teams, because the error message points at your call site while the actual cause is a package version you never deliberately chose.

This one is a five minute fix once you know the mapping. The interesting part is everything downstream of the rename: how you register `IChatClient` cleanly, keep provider swapping to a one line change, and stop a preview package from silently reshaping your build again. If you like working through that with annotated source code you can actually run, the deeper walkthroughs live on [Patreon](https://www.patreon.com/CodingDroplets).

Fixing the compile error is quick. Knowing what `GetStreamingResponseAsync` is supposed to look like once it is wired into a real endpoint, streaming tokens over Server-Sent Events with cancellation handled properly, is the part that actually matters. [Chapter 5 of AI-Powered .NET APIs](https://aiapis.codingdroplets.com/) builds exactly that inside one running ASP.NET Core support API, so the method is never floating in isolation.

[![AI-Powered .NET APIs](https://newsletter.codingdroplets.com/images/ai-api-course-banner-1.jpg align="center")](https://aiapis.codingdroplets.com/)

## What Does "IChatClient Does Not Contain a Definition for CompleteAsync" Actually Mean?

It means your code was written against a Microsoft.Extensions.AI version older than `9.3.0-preview.1.25114.11`, and you are now compiling against a newer one. The method still exists in spirit, under a new name. C# reports it as `CS1061` because from the compiler's point of view you are calling a member that is simply not on the interface.

Four renames landed together in that release:

| Old name (pre 9.3) | Current name |
| --- | --- |
| `CompleteAsync` | `GetResponseAsync` |
| `CompleteStreamingAsync` | `GetStreamingResponseAsync` |
| `ChatCompletion` | `ChatResponse` |
| `StreamingChatCompletionUpdate` | `ChatResponseUpdate` |

The pattern is consistent: the library moved away from "completion" language toward "response" language. Once you see that, every rename becomes guessable. A non streaming call returns a `ChatResponse`, and a streaming call returns `IAsyncEnumerable<ChatResponseUpdate>`.

So the old call becomes the new call with almost no structural change:

```csharp
// Pre 9.3 - no longer compiles
var completion = await client.CompleteAsync("What is AI?");

// Current
ChatResponse response = await client.GetResponseAsync("What is AI?");
```

And the streaming version, which is where most people meet this error, since streaming is the reason they reached for `IChatClient` in the first place:

```csharp
// Pre 9.3 - no longer compiles
await foreach (StreamingChatCompletionUpdate update in client.CompleteStreamingAsync(prompt))
    Console.Write(update);

// Current
await foreach (ChatResponseUpdate update in client.GetStreamingResponseAsync(prompt))
    Console.Write(update);
```

The loop body does not change. Only the method name and the update type do.

## Cause 1: Your Code Predates the Rename

This is the common case. You copied a sample published before the 9.3 preview, or you are working through a course recorded around the original November 2024 launch, and you installed the current package. The sample is internally consistent and simply describes an API that no longer exists.

**The fix:** apply the rename table above. Do not go hunting for a compatibility shim, and do not pin backwards to an old preview to make the red squiggles disappear. The names are stable now and the current package is where every other fix lives.

One detail worth knowing while you are in there: `ChatResponse` overrides `ToString()`, so `Console.WriteLine(response)` prints the text without you reaching for `.Text`. Small thing, but it explains why some samples show a bare `response` where others show `response.Text`.

## Cause 2: A Transitive Package Upgraded Abstractions Underneath You

This one is nastier because you never touched the package yourself, and it usually shows up at runtime rather than at build time:

```plaintext
Could not load type 'Microsoft.Extensions.AI.ChatCompletion' from assembly
'Microsoft.Extensions.AI.Abstractions, Version=9.3.0.0'
```

Here your code compiled against the old `ChatCompletion` type, but something else in the graph, commonly `Azure.AI.OpenAI` or the `OpenAI` package, pulled a newer `Microsoft.Extensions.AI.Abstractions` forward. NuGet resolved the higher version, the type your assembly was built against no longer exists, and you get a `TypeLoadException` on the first call instead of a clean compiler error.

**The fix:** find out what is actually being restored rather than what your `.csproj` says.

```bash
dotnet list package --include-transitive | findstr Extensions.AI
```

Once you can see the resolved version, reference `Microsoft.Extensions.AI` explicitly at the version you intend to use and let everything else align to it. A direct reference beats an accidental one. Then rebuild rather than running an incremental build, because a stale assembly is exactly what produced the mismatch.

The general lesson holds well beyond AI packages: a `TypeLoadException` naming a type you never wrote is nearly always a transitive version conflict, not a bug in your code.

## Cause 3: The IList to IEnumerable Signature Change

If you fixed the names and still have a build error, this is usually why. A later release, `9.3.0-preview.1.25161.3`, changed the `chatMessages` parameter on both `GetResponseAsync` and `GetStreamingResponseAsync` from `IList<ChatMessage>` to `IEnumerable<ChatMessage>`.

Calling code is almost always fine, since a `List<ChatMessage>` satisfies both. Two cases do break:

*   **Custom** `IChatClient` **implementations.** Your `override` no longer matches the interface, so it stops overriding anything. Update the parameter type to `IEnumerable<ChatMessage>`.
    
*   **Anything that indexed into the parameter,** such as `chatMessages[^1]`. `IEnumerable<T>` has no indexer. Reach for `.Last()`, or materialise once with `.ToList()` if you need repeated access.
    

If you wrap `IChatClient` for cross cutting behaviour, derive from `DelegatingChatClient` rather than implementing the interface by hand. It forwards `GetResponseAsync`, `GetStreamingResponseAsync`, and `Dispose` for you, so you override only what you are actually changing and signature churn touches far less of your code. That is the pattern we ship at Coding Droplets for anything resembling middleware, and it is the same instinct as our [enterprise guide to IChatClient in ASP.NET Core](https://codingdroplets.com/microsoft-extensions-ai-ichatclient-aspnet-core-enterprise-2026).

## Cause 4: You Are Still Referencing Microsoft.Extensions.AI.Ollama

If you are running models locally, there is a second trap waiting behind the rename. The `Microsoft.Extensions.AI.Ollama` package is deprecated, with no further updates, features, or fixes planned. Microsoft's guidance is to use [OllamaSharp](https://www.nuget.org/packages/OllamaSharp) instead, which implements `IChatClient` directly.

```csharp
using OllamaSharp;

IChatClient client = new OllamaApiClient(new Uri("http://localhost:11434/"), "phi3:mini");
Console.WriteLine(await client.GetResponseAsync("What is AI?"));
```

Because `OllamaApiClient` is an `IChatClient`, the rest of your pipeline does not care that the provider changed. That is the whole point of the abstraction. For OpenAI the shape is the same idea with a conversion at the edge:

```csharp
IChatClient client = new OpenAI.Chat.ChatClient("gpt-4o-mini", apiKey).AsIChatClient();
```

One `IChatClient`, swappable providers, and the calling code stays untouched.

## How to Fix It, Start to Finish

1.  **Check what version you are actually on.** Run `dotnet list package --include-transitive` and look for `Microsoft.Extensions.AI.Abstractions`. The resolved version is the one that matters, not the one in your project file.
    
2.  **Move to a current stable release.** Microsoft.Extensions.AI is well past the preview churn now, with `10.8.0` published in July 2026. The renames are not going to move again.
    
3.  **Apply the four renames.** `CompleteAsync`, `CompleteStreamingAsync`, `ChatCompletion`, and `StreamingChatCompletionUpdate` become `GetResponseAsync`, `GetStreamingResponseAsync`, `ChatResponse`, and `ChatResponseUpdate`. A find and replace across the solution handles nearly all of it.
    
4.  **Fix custom clients.** Change `IList<ChatMessage>` to `IEnumerable<ChatMessage>` on any hand written `IChatClient`, and remove indexer access.
    
5.  **Replace the deprecated Ollama package** with OllamaSharp if you are running local models.
    
6.  **Rebuild clean, then run.** `dotnet clean` first. A leftover assembly built against `ChatCompletion` will keep throwing `TypeLoadException` no matter how correct your source now is.
    

## How Do You Stop This Happening Again?

Pin the version and make upgrades a decision rather than an accident. Three habits carry most of the weight:

*   **Reference** `Microsoft.Extensions.AI` **directly** at an explicit version, even when a provider package already drags it in. An implicit dependency is one you cannot reason about.
    
*   **Prefer stable over preview** for anything you deploy. The 9.x preview line is precisely where these renames happened. On 10.x you are past it.
    
*   **Trust the package README over blog posts,** this one included. The NuGet readme ships with the version you installed, which means it cannot drift out of date the way a tutorial can. When a sample and the readme disagree, the readme is right.
    

It is also worth internalising why this churn happened at all. Microsoft.Extensions.AI is doing for AI clients what `ILogger` and `HttpClient` abstractions did for logging and HTTP: one interface, many providers, middleware you compose. Preview APIs earned their renames by being used. The naming settled once the shape was right, and the payoff is that swapping Ollama for Azure OpenAI is now a registration change rather than a rewrite. If you want to see where that leads, our walkthrough on [streaming LLM responses in ASP.NET Core with IChatClient](https://codingdroplets.com/stream-llm-responses-aspnet-core-ichatclient) picks up right where this fix leaves off.

## Frequently Asked Questions

**What replaced CompleteAsync in Microsoft.Extensions.AI?** `GetResponseAsync`. It takes the same inputs and returns a `ChatResponse` instead of the old `ChatCompletion`. The rename landed in `9.3.0-preview.1.25114.11` and the name has been stable since.

**What is the difference between GetResponseAsync and GetStreamingResponseAsync?** The inputs are identical. `GetResponseAsync` returns the whole `ChatResponse` once the model finishes. `GetStreamingResponseAsync` returns `IAsyncEnumerable<ChatResponseUpdate>`, giving you tokens as they arrive. Use streaming for anything a human waits on, because a multi second blank screen is the fastest way to lose a user.

**Why do I get "Could not load type Microsoft.Extensions.AI.ChatCompletion" at runtime when the build succeeded?** Your assembly was compiled against the old `ChatCompletion` type, but a transitive dependency pulled a newer `Microsoft.Extensions.AI.Abstractions` at restore time, where that type no longer exists. Run `dotnet list package --include-transitive`, add a direct reference at the version you want, then clean and rebuild.

**Can I keep using CompleteStreamingAsync by pinning an older preview version?** You can, and you should not. You would be freezing on a preview to preserve a name, and giving up every fix, provider update, and performance improvement since early 2025. The rename is mechanical. Do it once.

**Is Microsoft.Extensions.AI.Ollama still supported?** No. It is deprecated with no further updates, features, or fixes planned. Use OllamaSharp, whose `OllamaApiClient` implements `IChatClient` directly, so the rest of your pipeline stays exactly as it is.

**How do I convert my ChatResponseUpdate stream back into a single response?** Collect the updates and call `ToChatResponse()` on the resulting sequence. `AddMessages` is the related helper for folding a response, or a set of updates, back into your conversation history list. Both are covered in the [official IChatClient documentation](https://learn.microsoft.com/en-us/dotnet/ai/ichatclient).

* * *

## About the Author

I'm Celin Daniel, Co-founder of [Coding Droplets](https://codingdroplets.com/). I've been building .NET and ASP.NET Core systems in production for 13+ years - APIs, distributed backends, enterprise platforms. Everything I write here comes from real shipping experience: patterns that held up, trade-offs that bit us, and lessons learned the hard way.

*   GitHub: [codingdroplets](http://github.com/codingdroplets/)
    
*   YouTube: [Coding Droplets](https://www.youtube.com/@CodingDroplets)
    
*   Website: [codingdroplets.com](https://codingdroplets.com/)
