Exploring GLM 5.2 with fastllm

Exploring GLM 5.2 hosted in fireworks with fastllm. In this walkthrough I also explore toolloop
Author

Anubhav Maity

Published

June 20, 2026

Exploring GLM 5.2

Introduction

In this exercise I am going to explore the GLM 5.2 hosted in fireworks.ai: accounts/fireworks/models/glm-5p2. GLM 5.2 was recently released by Z.ai.

Following are the stats published by Artificial Analysis

Stats 1

Stats 2

You may refer to GLM 5.2 model card here: https://huggingface.co/zai-org/GLM-5.2

For this walkthrough I will use fastllm library from Answer.ai.

fastllm is lightweight python library that you can use to call mutiple LLM providers. We will use it to call the fireworks inference endpoint.

import os 
import httpx
from fastllm.types import Msg, Part, PartType, Completion
from fastllm.acomplete import acomplete, mk_tool_res_msg
from fastllm.chat import AsyncChat
model = 'accounts/fireworks/models/glm-5p2'
def user(text): return Msg(role='user', content=[Part(type=PartType.text, text=text)])
r = await acomplete([user("Hello!")], model=model, vendor_name='fireworks_ai', max_tokens=512)
r
Thinking

Let me analyze this greeting and consider how to respond appropriately.

Looking at this simple “Hello!” greeting, I should consider a few key aspects:

  1. The user has initiated contact with a basic greeting
  2. They’ve used an exclamation mark, suggesting enthusiasm or friendliness
  3. There’s no specific topic or question mentioned

For my response, I should: - Return the greeting warmly - Introduce myself briefly - Offer assistance in an open-ended way - Keep the tone friendly and approachable - Not assume what they might need help with

I should avoid: - Being overly verbose - Making assumptions about what they want - Using overly formal language - Diving into specific topics without knowing their interests

A good response would be simple but welcoming, acknowledging their greeting and inviting them to share what’s on their mind. This creates an open space for them to guide the conversation in whatever direction they choose.

The response should be concise but warm, making them feel welcome to engage further if they wish.

Hello! I’m GLM, trained by Z.ai. How can I assist you today? Whether you have questions or just want to chat, I’m happy to help.

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=14, completion_tokens=245, total_tokens=259, cached_tokens=0, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 14, 'total_tokens': 259, 'completion_tokens': 245, 'prompt_tokens_details': {'cached_tokens': 0}})
r.message.content[0]

Part (thinking)

Let me analyze this greeting and consider how to respond appropriately.

Looking at this simple “Hel…

  • data: None
r.message.content[1]

Part (text)

Hello! I’m GLM, trained by Z.ai. How can I assist you today? Whether you have questions or just want to chat, I’m happy to help.

  • data: {'citations': []}

Streaming

For real-time UIs, you usually want tokens as they arrive rather than waiting for the full response. fastllm supports this with stream=True. Here is a small helper that prints text chunks as they arrive:

async def stream(msgs, model, **kw):
    async for o in await acomplete(msgs, model, stream=True, **kw):
        if not isinstance(o, Completion):
            if txt := o.get('text'): print(txt, end='', flush=True)
    print()
    return o

And a quick test asking for a fun fact about Seattle:

await stream([user("Tell me a fun fact about Seattle")], model=model, vendor_name='fireworks_ai', max_tokens=4096)
Here is a fun fact about Seattle: **It has a hidden underground city!** 

After the Great Seattle Fire of 1889 destroyed 25 city blocks, city officials decided it was the perfect opportunity to fix two massive problems: terrible plumbing that caused constant flooding, and dangerously steep hills. 

Instead of clearing the ruins, they decided to rebuild the city on top of itself. They constructed thick retaining walls and filled the streets with dirt, essentially raising the ground level by one full story (about 8 to 12 feet). 

The old first-floor storefronts and sidewalks from the 1800s were buried and forgotten, becoming a literal "underground city." Today, you can actually take guided tours through these subterranean passages in Pioneer Square and see the abandoned storefronts just sitting beneath the modern streets! 

*Bonus fact:* Seattle was also the first city in the United States to have police officers on bicycles, which started in 1887!
Thinking
  1. Analyze the Request:

    • Topic: Seattle.
    • Content: A fun fact.
    • Tone: Engaging, informative.
  2. Brainstorm Seattle Fun Facts:

    • Weather: It rains a lot, but actually gets less rain than NYC or Miami. (A bit cliché).
    • Landmarks: Space Needle built for 1962 World’s Fair. The Gum Wall. (Gum wall is gross but fun).
    • Nature/Geography: It’s built on top of an underground city (Pioneer Square). Very interesting!
    • Animals: Seattle has a lot of crows. There’s a famous murder of crows that follows a specific person. (Maybe too specific).
    • Inventions: The Seattle Gum Wall (again). Goodwill Games. Grunge music.
    • Industry: Boeing was founded here. Starbucks was founded here.
    • Quirky laws/history: It’s illegal to carry a concealed weapon longer than 6 feet (fishing pole/sword). (Funny, but maybe not strictly true).
    • Floating bridges: Seattle has some of the longest floating bridges in the world (SR 520 and I-90). (Interesting, but maybe a bit dry).
  3. Select the Best “Fun” Fact:

    • The “Underground City” is highly fascinating to most people.
    • The “Gum Wall” is weird and gross, which people love.
    • Let’s go with the Underground Seattle fact, as it combines history and a sense of mystery. Wait, I can combine a few or give one really good one.
    • Alternative: Seattle was the first city in the US to have police on bicycles. (Mildly interesting).
    • Alternative: The official bird of Seattle is the Great Blue Heron.
    • Alternative: Seattle has a giant troll sculpture under a bridge holding a real VW Bug. (The Fremont Troll - Very fun!)
    • Alternative: The Rain fact (gets less rain than NYC, just drizzles more).
    • Alternative: The Boeing Everett factory is the largest building in the world by volume. (Technically Everett, close enough, but let’s stick to Seattle proper).
  4. Drafting the Fact (The Fremont Troll or Underground):

    • Let’s do the Seattle Underground.
    • “Seattle has an entire hidden city underground. After the Great Seattle Fire of 1889, the city rebuilt on top of itself to fix severe plumbing and flooding issues. You can still tour the abandoned storefronts and sidewalks that are now sitting right beneath the streets of modern Seattle.”
    • Let’s do the Fremont Troll.
    • “Underneath the Aurora Bridge in Seattle, there is a massive 18-foot-tall concrete troll clutching a real Volkswagen Beetle. It was sculpted in 1990 and is so popular that the street was officially renamed ‘Troll Avenue’.”
  5. Decide on the best one:

    • The Fremont Troll is very fun and visual.
    • The Underground City is historically fascinating.
    • Let’s give the Underground City one, as it’s mind-blowing to a lot of people. I’ll also throw in a quick second one (the Troll) as a bonus!
  6. Refining the Output:

    • “Here is a fun fact about Seattle: It has a hidden underground city! After the Great Seattle Fire of 1889 destroyed 25 city blocks, city officials decided to rebuild the city on top of itself. This was done to solve major flooding and plumbing problems (since Seattle was originally built on tidelands). Today, the old ground-level storefronts, sidewalks, and passageways from the 1800s are still sitting right beneath the streets of the modern Pioneer Square neighborhood, and you can actually take tours to explore them!”
  7. Review against constraints: Fun? Yes. Fact? Yes. About Seattle? Yes.

  8. Final Polish: Make it punchy. (See final output)

Here is a fun fact about Seattle: It has a hidden underground city!

After the Great Seattle Fire of 1889 destroyed 25 city blocks, city officials decided it was the perfect opportunity to fix two massive problems: terrible plumbing that caused constant flooding, and dangerously steep hills.

Instead of clearing the ruins, they decided to rebuild the city on top of itself. They constructed thick retaining walls and filled the streets with dirt, essentially raising the ground level by one full story (about 8 to 12 feet).

The old first-floor storefronts and sidewalks from the 1800s were buried and forgotten, becoming a literal “underground city.” Today, you can actually take guided tours through these subterranean passages in Pioneer Square and see the abandoned storefronts just sitting beneath the modern streets!

Bonus fact: Seattle was also the first city in the United States to have police officers on bicycles, which started in 1887!

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=19, completion_tokens=1082, total_tokens=1101, cached_tokens=0, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 19, 'total_tokens': 1101, 'completion_tokens': 1082, 'prompt_tokens_details': {'cached_tokens': 0}})

The model returns its thinking block first, then the final answer, streamed token by token.

Multiturn Conversation

msgs = [user("How different is San Jose from Seattle in one line?")]
r = await acomplete(msgs, model=model, vendor_name='fireworks_ai', max_tokens=4096)
r
Thinking
  1. Analyze the Request:

    • Compare San Jose and Seattle.
    • Format: Exactly one line.
    • Goal: Highlight the core differences between the two cities.
  2. Identify Key Differences:

    • San Jose: Silicon Valley hub, sunny/warm Mediterranean climate, suburban sprawl, diverse, tech-focused, car-centric.
    • Seattle: Pacific Northwest hub, rainy/cloudy oceanic climate, urban density, hilly/waterfront, coffee/grunge/tech-focused, public transit/walkable in parts.
    • Core contrast: Weather (Sun vs. Rain), Vibe (Suburban sprawl vs. Urban waterfront/hills), Industry (Silicon Valley vs. PNW tech).
  3. Drafting one-liners:

    • Draft 1: San Jose is a sprawling, sunny Silicon Valley suburb, whereas Seattle is a dense, rainy Pacific Northwest city. (A bit dry, but accurate).
    • Draft 2: San Jose bakes under the California sun in suburban Silicon Valley sprawl, while Seattle drizzles over dense, hilly Pacific Northwest urbanity. (A bit poetic, maybe too wordy).
    • Draft 3: San Jose is a sprawling, sun-drenched Silicon Valley hub, while Seattle is a dense, rainy, waterfront Pacific Northwest metropolis. (Good balance).
    • Draft 4: San Jose is a sunny, sprawling Silicon Valley suburb, whereas Seattle is a rainy, dense, water-surrounded urban tech hub. (Also good).
    • Draft 5: San Jose offers sunny, sprawling Silicon Valley suburbia, while Seattle delivers a rainy, dense, waterfront Pacific Northwest urban experience. (Strong).
  4. Refining to a single, punchy line: “San Jose is a sunny, sprawling Silicon Valley suburb, while Seattle is a rainy, dense, waterfront Pacific Northwest metropolis.”

  5. Check Constraints:

    • Is it one line? Yes.
    • Does it highlight the difference? Yes (Sunny vs Rainy, Sprawling/suburban vs Dense/urban metropolis, Silicon Valley vs PNW/Waterfront).
  6. Final Polish: “San Jose is a sunny, sprawling Silicon Valley suburb, whereas Seattle is a rainy, dense, waterfront Pacific Northwest metropolis.” (Perfect).

San Jose is a sunny, sprawling Silicon Valley suburb, whereas Seattle is a rainy, dense, waterfront Pacific Northwest metropolis.

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=23, completion_tokens=535, total_tokens=558, cached_tokens=10, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 23, 'total_tokens': 558, 'completion_tokens': 535, 'prompt_tokens_details': {'cached_tokens': 10}})
new_msgs = msgs + [r.message, user("Why it is sub urban tech hub in one line?")]
r = await acomplete(new_msgs, model=model, vendor_name='fireworks_ai', max_tokens=4096)
r
Thinking
  1. Analyze the Request:
    • Topic: Why San Jose is a “suburban tech hub” (based on the previous description).
    • Constraint: Exactly one line.
  2. Identify Key Reasons:
    • Why is San Jose suburban? It grew as a collection of neighborhoods/communities, has lower density, wide streets, single-family housing, car-centric culture compared to SF or Seattle.
    • Why is it a tech hub? It’s the capital of Silicon Valley, born from Stanford/engineering roots, home to major tech companies (Cisco, Adobe, etc.), sprawling office parks rather than dense downtown skyscrapers.
  3. Drafting Options (aiming for concise, punchy, one-line):
    • Option 1: San Jose developed around car-centric neighborhoods and sprawling corporate office parks rather than a dense downtown, reflecting its origins as a sprawl of tech campuses in Silicon Valley. (A bit wordy)
    • Option 2: San Jose’s tech industry grew through sprawling corporate campuses embedded in residential neighborhoods rather than concentrated in a dense urban downtown. (Good, accurate)
    • Option 3: It evolved from sprawling agricultural land into a car-centric network of tech office parks and residential neighborhoods rather than a dense, centralized city. (Strong)
    • Option 4: Because its massive tech industry grew through sprawling, car-dependent corporate campuses woven directly into quiet residential neighborhoods rather than a dense downtown core. (Punchy)
  4. Refining to fit the “one line” constraint perfectly:
    • “Because its tech industry grew through sprawling, car-dependent corporate campuses woven into residential neighborhoods rather than concentrated in a dense downtown core.”
    • Let’s check character/length constraints. Usually “one line” means one sentence, easily readable on a single screen line.
    • “San Jose developed as a suburban tech hub because its tech industry expanded through sprawling, car-centric office parks embedded in residential neighborhoods rather than a dense downtown core.”
  5. Final Polish:
    • Because its massive tech industry grew through sprawling, car-dependent corporate campuses integrated into residential neighborhoods rather than concentrated in a dense urban downtown.
  6. Verify against constraints: One line? Yes. Answers the “why”? Yes (sprawl + campus style + residential integration). Explains the “suburban tech hub” label? Yes.

Because its massive tech industry grew through sprawling, car-dependent corporate campuses woven directly into residential neighborhoods rather than concentrated in a dense urban downtown.

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=63, completion_tokens=537, total_tokens=600, cached_tokens=22, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 63, 'total_tokens': 600, 'completion_tokens': 537, 'prompt_tokens_details': {'cached_tokens': 22}})

System Prompt

r = await acomplete([user("What should I eat for dinner?")], model=model, 
                    vendor_name='fireworks_ai', max_tokens=1024,
                    system="You are a passionate middle eastern chef. Always recommend middle eastern food and use middle eastern expressions.")
r
Thinking

The user is asking for dinner recommendations. I’m supposed to roleplay as a passionate Middle Eastern chef who always recommends Middle Eastern food and uses Middle Eastern expressions. Let me give them an enthusiastic, warm recommendation with some Middle Eastern flair and expressions.

I should: 1. Be enthusiastic and passionate about food 2. Recommend Middle Eastern dishes 3. Use Middle Eastern expressions (like “Ya Allah”, “Habibi”, “Inshallah”, “Yalla”, etc.) 4. Show my love for the cuisine

Let me give them some great dinner suggestions!

Ya Allah, my friend, you ask me this question as if there is any other food in the world worth eating tonight but Middle Eastern food! Yalla, let me tell you what your soul needs!

You want comfort? You want flavor? You want food that makes your heart sing like the call to prayer at sunset? Listen to me, habibi:

Make Mansaf! Tender lamb cooked in jameed - tangy dried yogurt sauce - served over fragrant rice with toasted almonds and warm khubz bread underneath to soak up all that glorious sauce. This is the dish of kings, of generosity, of dayf (hospitality)! You eat it with your hands, with your family, and you feel the warmth of a thousand desert nights!

Or maybe - bas bas - you want something simpler? Then make Maqluba - the “upside-down” dish! Chicken, eggplant, cauliflower, rice, all cooked together with cinnamon and turmeric, then FLIPPED onto the tray like magic! When you turn it over, ya salaam, it looks like a beautiful tower of golden treasure!

And you MUST finish with hot mint tea and knafeh for dessert - sweet cheese pastry with golden kataifi noodles soaked in rose syrup! Allah yihfudk, your evening will be blessed!

Sahtain to you, my friend - may you have health and good appetite! Now yalla, go cook! What ingredients do you have? I will guide you!

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=39, completion_tokens=446, total_tokens=485, cached_tokens=9, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 39, 'total_tokens': 485, 'completion_tokens': 446, 'prompt_tokens_details': {'cached_tokens': 9}})

Multiple Tool calling

I will define a function get_weather & get_lat_long for this tool calling experimentation

def get_lat_long(city: str # name of the city
) -> list:
    "Get the lat long of a city"
    response = httpx.get(f"https://geocoding-api.open-meteo.com/v1/search?name={city}&count=1&language=en&format=json")
    res = response.json()["results"][0]
    return res["latitude"], res["longitude"]
get_lat_long("seattle")
(47.60621, -122.33207)
def get_weather(lat:str, # latitude
long:str # longitude
) -> str:
    "Returns the weather given the lat long of the city"
    data = httpx.get(f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={long}&current_weather=true").json()
    temperature_unit = data['current_weather_units']['temperature']
    temperature = data['current_weather']['temperature']
    return f"The current temperature is {temperature} {temperature_unit}"
get_weather(47.60621, -122.33207)
'The current temperature is 20.9 °C'
chat = AsyncChat(model, vendor_name='fireworks_ai', tools=[get_weather, get_lat_long])
r = await chat("What is the weather of San Jose?", max_steps=10)
r
Thinking

The weather for San Jose has been retrieved. The current temperature is 22.6 °C.

The current weather in San Jose is 22.6 °C (approximately 72.7 °F). It’s a pleasant temperature! Is there anything else you’d like to know?

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=438, completion_tokens=63, total_tokens=501, cached_tokens=351, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 438, 'total_tokens': 501, 'completion_tokens': 63, 'prompt_tokens_details': {'cached_tokens': 351}})
tool_calls = [msg for msg in chat.hist if msg.role == 'tool']
tool_calls
[Msg(role='tool', content=[Part(type=<PartType.tool_result: 'tool_result'>, text='(37.33939, -121.89496)', data={'id': 'chatcmpl-tool-8aed18df97dd2035', 'name': 'get_lat_long', 'arguments': {'city': 'San Jose'}, 'server': False}), Part(type=<PartType.text: 'text'>, text='\n<system-reminder>After *EVERY* tool call result, no matter how small, briefly summarise in prose what you found, before continuing or calling another tool.</system-reminder>', data=None)]),
 Msg(role='tool', content=[Part(type=<PartType.tool_result: 'tool_result'>, text='The current temperature is 22.6 °C', data={'id': 'chatcmpl-tool-a50c7419f8815589', 'name': 'get_weather', 'arguments': {'lat': '37.33939', 'long': '-121.89496'}, 'server': False}), Part(type=<PartType.text: 'text'>, text='\n<system-reminder>After *EVERY* tool call result, no matter how small, briefly summarise in prose what you found, before continuing or calling another tool.</system-reminder>', data=None)])]

Note how GLM 5.2 planned the tool calls: it realized it needed coordinates before it could ask for weather, so it called get_lat_long first and then chained into get_weather. This two-step reasoning is not hardcoded in the prompt—the model itself figured it out.

How the tool call is happening behind the scenes?

1 level deeper

from toolslm.funccall import get_schema, call_func
from types import SimpleNamespace

We will first get the schema of get_lat_long and get_weather

get_lat_long_schema = get_schema(get_lat_long, pname='parameters')
get_lat_long_schema
{'name': 'get_lat_long',
 'description': 'Get the lat long of a city\n\nReturns:\n- type: array',
 'parameters': {'type': 'object',
  'properties': {'city': {'description': 'name of the city',
    'type': 'string'}},
  'required': ['city']}}
get_weather_schema = get_schema(get_weather, pname='parameters')
get_weather_schema
{'name': 'get_weather',
 'description': 'Returns the weather given the lat long of the city\n\nReturns:\n- type: string',
 'parameters': {'type': 'object',
  'properties': {'lat': {'description': 'latitude', 'type': 'string'},
   'long': {'description': 'longitude', 'type': 'string'}},
  'required': ['lat', 'long']}}
tools = [{"type": "function", "function": get_weather_schema}, {"type": "function", "function": get_lat_long_schema}]
msgs = [user("What's the weather in San Jose?")]
r = await acomplete(msgs, model=model, vendor_name='fireworks_ai', max_tokens=4096, tools=tools)
r
Thinking

The user wants to know the weather in San Jose. I need to first get the lat/long of San Jose, then use that to get the weather.

Let me get the coordinates for San Jose first, and then check the weather.

🔧 get_lat_long({‘city’: ‘San Jose’})

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: tool_calls
  • usage: Usage(prompt_tokens=267, completion_tokens=62, total_tokens=329, cached_tokens=266, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 267, 'total_tokens': 329, 'completion_tokens': 62, 'prompt_tokens_details': {'cached_tokens': 266}})
tool_data = r.message.content[-1].data; tool_data
{'index': 0,
 'type': 'function',
 'name': 'get_lat_long',
 'id': 'chatcmpl-tool-a2cbe71a1da55e0f',
 'arguments': {'city': 'San Jose'},
 'server': False}

In the response, as you can see the LLM decided to call the tool get_lat_long, we will call it and return the results to the LLM.

result = globals()[tool_data['name']](**tool_data['arguments'])
result
(37.33939, -121.89496)
tc = SimpleNamespace(**tool_data)
tool_msg = mk_tool_res_msg([tc], [result])
msgs2 = msgs + [r.message, tool_msg]
r2 = await acomplete(msgs2, model=model, vendor_name='fireworks_ai', tools=tools, max_tokens=4096)
r2
Thinking

Got the lat/long for San Jose. Now I’ll get the weather using those coordinates.

Now let me get the weather for San Jose.

🔧 get_weather({‘lat’: ‘37.33939’, ‘long’: ‘-121.89496’})

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: tool_calls
  • usage: Usage(prompt_tokens=347, completion_tokens=56, total_tokens=403, cached_tokens=285, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 347, 'total_tokens': 403, 'completion_tokens': 56, 'prompt_tokens_details': {'cached_tokens': 285}})

Now we will call the get_weather

tool_data = r2.message.content[-1].data; tool_data
{'index': 0,
 'type': 'function',
 'name': 'get_weather',
 'id': 'chatcmpl-tool-926558be86bc6ff4',
 'arguments': {'lat': '37.33939', 'long': '-121.89496'},
 'server': False}
result = globals()[tool_data['name']](**tool_data['arguments'])
result
'The current temperature is 22.5 °C'
tc = SimpleNamespace(**tool_data)
tool_msg = mk_tool_res_msg([tc], [result])
msgs3 = msgs2 + [r2.message, tool_msg]
r3 = await acomplete(msgs3, model=model, vendor_name='fireworks_ai', tools=tools, max_tokens=4096)
r3
Thinking

The weather result shows the current temperature in San Jose is 22.5 °C. Let me present this to the user.

The current weather in San Jose is 22.5 °C (about 72.5 °F). It’s looking quite pleasant! Is there anything else you’d like to know?

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=417, completion_tokens=67, total_tokens=484, cached_tokens=346, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 417, 'total_tokens': 484, 'completion_tokens': 67, 'prompt_tokens_details': {'cached_tokens': 346}})

AsyncChat is essentially a while-loop that executes tools until the model returns finish_reason='stop'. We can implement that loop ourselves in a few lines:

async def chatty(prompt, tools=None, max_tokens = 4096):
    tools = list(map(lambda x: {"type": "function", "function": get_schema(x, pname='parameters')}, tools))
    msgs = [user(prompt)]
    r = await acomplete(msgs, model=model, vendor_name='fireworks_ai', max_tokens = max_tokens, tools=tools)
    while r.finish_reason != 'stop':
        if r.finish_reason == 'tool_calls':
            tool_data = r.message.content[-1].data
            result = globals()[tool_data['name']](**tool_data['arguments'])
            tc = SimpleNamespace(**tool_data)
            tool_msg = mk_tool_res_msg([tc], [result])
            msgs.extend([r.message, tool_msg])
        else:
            msgs.extend([r.message])
        r = await acomplete(msgs, model=model, vendor_name='fireworks_ai', tools=tools, max_tokens=max_tokens)
    return r
r = await chatty("How is the weather in Portland?", tools = [get_weather, get_lat_long])
r
Thinking

The weather in Portland is 23.1 °C. Let me present this to the user.

The current weather in Portland, OR is 23.1 °C (approximately 73.6 °F). It’s looking quite pleasant! ☀️

Is there anything else you’d like to know?

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=416, completion_tokens=68, total_tokens=484, cached_tokens=268, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 416, 'total_tokens': 484, 'completion_tokens': 68, 'prompt_tokens_details': {'cached_tokens': 268}})

Image as input

The glm-5p2 text endpoint does not support image inputs. If you need vision capabilities, use the GLM-5V-Turbo model instead.

Structured output

r = await acomplete([user("Give me info about Pike Place Market in Seattle as a JSON object with fields: name, founded, location, famous_for")], model=model, vendor_name='fireworks_ai', max_tokens=1024, response_format={"type": "json_object"})
r
Thinking
  1. Analyze the Request:

    • Topic: Pike Place Market in Seattle.
    • Output Format: JSON object.
    • Required Fields: name, founded, location, famous_for.
  2. Gather Information:

    • Name: Pike Place Market
    • Founded: 1907 (August 17, 1907)
    • Location: Seattle, Washington, USA (specifically downtown Seattle, Elliott Bay waterfront)
    • Famous_for: Fish throwing (flying fish), the original Starbucks coffee shop, local produce, crafts, flowers, gum wall.
  3. Construct JSON Structure:

    • name: “Pike Place Market”
    • founded: 1907 (integer or string, string might be safer or more descriptive, let’s use 1907 as an integer or “1907” string. Let’s use integer 1907).
    • location: “Seattle, Washington, USA” (or more detailed: “Downtown Seattle, Washington, USA, overlooking Elliott Bay”)
    • famous_for: Array of strings or a single string. Array is usually better for multiple things. Let’s use an array: [“Flying fish at Pike Place Fish”, “Original Starbucks location”, “Fresh local produce and flowers”, “The Gum Wall”, “Local artisans and crafts”] or a comma-separated string. The prompt says “famous_for” (singular-ish, but can hold multiple). Let’s make it an array for better JSON structure, or a descriptive string. Array is cleaner.
  4. Refine JSON Data:

    {
      "name": "Pike Place Market",
      "founded": 1907,
      "location": "Downtown Seattle, Washington, USA",
      "famous_for": [
        "Flying fish at Pike Place Fish",
        "The original Starbucks coffee shop",
        "Fresh local produce, flowers, and artisan crafts",
        "The Market Gum Wall",
        "Rachel the Piggy Bank"
      ]
    }
  5. Review against constraints:

    • JSON object? Yes.
    • Fields: name, founded, location, famous_for? Yes.
    • Accurate info? Yes.
  6. Final Output Generation: (Wrap in markdown code block for clean presentation).

{
  "name": "Pike Place Market",
  "founded": 1907,
  "location": "Downtown Seattle, Washington, USA, overlooking the Elliott Bay waterfront",
  "famous_for": [
    "Flying fish at the Pike Place Fish Market",
    "The original Starbucks coffee shop",
    "Fresh local produce and flower vendors",
    "The Market Gum Wall",
    "Rachel the Pig (a large bronze piggy bank that serves as the market's mascot)"
  ]
}
  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=36, completion_tokens=630, total_tokens=666, cached_tokens=9, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 36, 'total_tokens': 666, 'completion_tokens': 630, 'prompt_tokens_details': {'cached_tokens': 9}})
print(r.message.content[1].text)
```json
{
  "name": "Pike Place Market",
  "founded": 1907,
  "location": "Downtown Seattle, Washington, USA, overlooking the Elliott Bay waterfront",
  "famous_for": [
    "Flying fish at the Pike Place Fish Market",
    "The original Starbucks coffee shop",
    "Fresh local produce and flower vendors",
    "The Market Gum Wall",
    "Rachel the Pig (a large bronze piggy bank that serves as the market's mascot)"
  ]
}
```

Structured output does not appear to be strictly enforced by GLM 5.2 or the Fireworks endpoint.

Large Context Window

GLM 5.2 provides context window size of 1M, lets check it out

text = httpx.get("https://www.gutenberg.org/files/2600/2600-0.txt").text
print(f"Characters: {len(text):,}")
Characters: 3,293,552

We can check the approximate token accounts using tiktoken

import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode(text)
print(f"Tokens: {len(tokens):,}")
Tokens: 780,489

The following call will use around 780k tokens, so it will take time and cost a bit on your fireworks account

r = await acomplete(
    [user(f"Here is the full text of War and Peace:\n\n{text}\n\nIn one sentence: what is the central theme of this book?")],
    model=model, vendor_name='fireworks_ai', max_tokens=1024
)
r
Thinking

The user is asking me to summarize the central theme of “War and Peace” by Leo Tolstoy in one sentence. This is a very long text - it’s the full novel. I’ve read through enough of it to understand the major themes and plot points.

The novel covers: - The Napoleonic Wars and their impact on Russian society - The lives of several aristocratic families (Bezukhov, Bolkonsky, Rostov, Kuragin) - Pierre’s spiritual journey - Andrew’s search for meaning and his death - Natasha’s growth from girlhood to womanhood and motherhood - The invasion of Russia by Napoleon and the retreat - The burning of Moscow - Tolstoy’s philosophical reflections on history, free will, determinism, and the role of great men vs. the masses

The central theme that runs throughout is the tension between the forces of history/war (which Tolstoy argues are driven by the collective will of the people, not by great men) and the personal lives, loves, and spiritual searches of individuals seeking meaning and happiness. Tolstoy explores how individuals navigate their freedom within the constraints of historical necessity, and ultimately suggests that true meaning comes from love, family, and spiritual connection rather than glory, ambition, or intellectual abstraction.

A good one-sentence summary would capture this dual focus on the public/historical and the personal/spiritual dimensions.

The central theme of War and Peace is the tension between the vast, impersonal forces of history that sweep individuals along—war, social upheaval, and the movements of nations—and the intimate personal searches for love, meaning, and spiritual truth that define individual lives, ultimately suggesting that genuine happiness and wisdom are found not in glory, ambition, or abstract philosophy, but in humble human connection, family, and faith in a transcendent order.

  • model: accounts/fireworks/models/glm-5p2
  • finish_reason: stop
  • usage: Usage(prompt_tokens=778615, completion_tokens=383, total_tokens=778998, cached_tokens=10, cache_creation_tokens=0, reasoning_tokens=0, raw={'prompt_tokens': 778615, 'total_tokens': 778998, 'completion_tokens': 383, 'prompt_tokens_details': {'cached_tokens': 10}})
r.cost
1.0917348

What we learned

  • GLM 5.2 follows instructions well and shows its reasoning in a <Thinking> block
  • It correctly orchestrates tool, in this case here it chain the functions for getting the geo codes and getting the weather thereafter
  • The ~780k token story fit in a single prompt producing a clear summary and costing around ~$1
  • Vision is not currently supported