02 · Multi-turn with Server Conversations

How to keep a conversation's history on the Foundry service instead of in local memory, so the client never resends the transcript.

Part 41 of 91 Microsoft Agent Framework Go — Every Lesson

What this lesson demonstrates

The previous lesson kept history in a client-side session. This one moves it to the server: you create a Foundry project conversation once, bind its ID into an agent.Session, and pass that session to every run. Because the transcript lives in the service, turn 2 (“add emojis…”) and turn 3 (“another joke, but a ninja”) remember the earlier turns without the client ever resending them.

Binding a session to a server conversation

The distinctive move is creating the project conversation and wiring its ID into the session with agent.WithServiceID:

// (1) Create a server-side project conversation and bind a Session to its ID.
conversationID, err := createProjectConversation(ctx, endpoint, cred)
// ...
session, err := a.CreateSession(ctx, agent.WithServiceID(conversationID))
// ...

// (2) Turn 1 — establish a joke; the server now keeps the transcript.
resp, err := a.RunText(ctx, "Tell me a joke about a pirate.",
    agent.WithSession(session)).Collect()

From here every RunText threads the same session. The last turn even switches to streaming (agent.Stream(true)) over the identical server conversation, proving the transport doesn’t care whether you collect or stream.

What to notice

The project conversation is created directly against the OpenAI-compatible endpoint. createProjectConversation builds an openai.NewClient pointed at {endpoint}/openai/v1/ with azure.WithTokenCredential and the scope https://ai.azure.com/.default, then calls client.Conversations.New. That returns a conversation ID — the thing you hand to WithServiceID.

The gotcha: this whole flow is live. Creating the project conversation is itself a network call, so unlike the client-side session lesson, there’s no way to exercise the real path offline. The structural test still builds the agent with a fake credential and asserts the logging middleware is attached, but the server-conversation path is gated behind AF_LIVE=1.

Watch the OAuth scope, too. The provider’s own model calls use one credential path, but the conversations client explicitly requests the https://ai.azure.com/.default resource scope — get that wrong and conversation creation fails with an auth error even though model calls would succeed.

How it maps to Foundry

Server-side conversations are Foundry’s answer to “I don’t want to ship the whole history on every request.” The service owns the transcript; the client sends only the new turn plus the conversation ID. That’s cheaper on the wire, survives client restarts, and is the foundation the persisted-conversation and observability lessons build toward.

Run it

go run ./tutorial/02-agents/providers/foundry/step02_2_multiturn_with_server_conversations

Needs az login and FOUNDRY_PROJECT_ENDPOINT; the live path is gated behind AF_LIVE=1.


Next: step03 · Function Tools (Foundry)

Sources & References

The Go SDK this lesson exercises
Server-side conversation history on Azure AI Foundry