Back to Bytes

Add system prompt extraction and stop_reason mapping to unified enum — lab audio overview

2026-04-21

Implement system prompt extraction that separates system-role messages into the Anthropic top-level system parameter, and map Anthropic stop_reason values (end_turn, max_tokens, stop_sequence) to the unified FinishReason enum. Build a message preparation pipeline and a complete stream_chat method th

GenAI Application Engineering › Full-Stack GenAI Applications › Chapter 1 · Chat Completion API with Streaming › Implement an Anthropic Claude streaming adapter

5:54
Implement system prompt extraction that separates system-role messages into the Anthropic top-level system parameter, and map Anthropic stop_reason values (end_turn, max_tokens, stop_sequence) to the unified FinishReason enum. Build a message preparation pipeline and a complete stream_chat method th
Share

More from this chapter

Transcript
Host: Welcome back. You're in Full-Stack GenAI Applications — the course about building complete, production-grade apps powered by large language models, or LLMs for short. This chapter is called Chat Completion API with Streaming, and it's all about sending model output back to users one word at a time, the way you see text appear letter by letter in tools like ChatGPT. This specific exercise — the final one in a three-part sequence — is the piece that ties the whole thing together. Expert: Picture a mid-sized company — maybe a hundred engineers, a few product teams — building a customer support assistant. They started on one model provider, say OpenAI. Six months in, the finance team pushes back on costs and asks if they can route some traffic to Anthropic's Claude to save money. The product manager says yes, great idea, swap it out. And that's when the trouble starts. Because every provider speaks a slightly different dialect. One expects the system instruction — the behind-the-scenes rules that tell the model how to behave, things like "you are a helpful support agent" — mixed in with the rest of the conversation. Another expects that instruction pulled out and handed over in its own separate slot. And when the model finishes generating, each provider uses its own words to describe why it stopped. If your app doesn't translate all of that into one shared internal language, your code ends up full of provider-specific branches, and every new model takes weeks to integrate. That's the real pain this exercise solves. Host: In the previous exercise, you built the piece that listens to Anthropic's live stream of events — the part that grabs each token as it arrives and passes it along. Now you're extending that adapter so it's feature-complete. So what exactly will we build? Expert: Three things, and they snap together into one clean pipeline. First, you'll write the piece that takes a list of chat messages and pulls out the system instruction — that hidden prompt that sets the model's personality and rules. Your code will scan the messages, lift the system instruction out, and hand it to Anthropic in the separate slot it expects. Second, you'll write a small translator that maps Anthropic's stop reasons — the short labels Anthropic uses to say why generation ended — into your app's own shared vocabulary. Anthropic has three main labels: one meaning the model finished naturally, one meaning it hit the maximum length you allowed, and one meaning it bumped into a stop word you configured. Your job is to turn each of those into the single internal label your whole application already understands. And third, you'll assemble the full streaming entry point — the one function a caller uses to start a conversation. It sets up the connection, prepares the messages, runs the stream, and emits a clean finish signal at the end. Here's the key idea, the real aha moment: every provider is a dialect, and your adapter is the translator. You don't ask the rest of your app to learn Anthropic's dialect. You teach this one file to speak it, so everything upstream stays provider-neutral. Host: Before you start, what's the one thing that tends to trip people up here? Expert: The stop-reason mapping looks tiny, but it hides a gotcha. When the stream ends, the final stop label doesn't arrive on the normal token events — it comes out of a summary object that the streaming client only produces after the stream is fully drained. So you have to wait until the end of the loop, reach into that summary, pull the label, and only then emit your finish event. A very common mistake is to try to read the stop reason mid-stream, where it simply isn't available yet, and you end up with a blank value or a crash. The other small trap: if there are no system messages at all in the conversation, don't hand Anthropic an empty string — just skip passing a system instruction entirely. Those two habits will save you an afternoon of debugging. Host: After this exercise, you'll be able to take a stream of chat messages, route it to Anthropic, deliver tokens live to the user, and report back in a single unified way why generation stopped — without the rest of your code ever knowing which provider answered. That's the foundation your team can build a multi-provider routing layer on top of. And with this done, you've completed the full Anthropic streaming adapter — a working, production-shaped piece you can bring straight into your team's architecture discussions about provider portability. Nice work getting here. Thanks for listening, and good luck with the build.

Want to go deeper? Explore disciplines with hands-on labs, quizzes, and chapter podcasts.