# GLM-5.2 > Open-weight (MIT) thinking model for agentic coding and long-horizon reasoning, with a 1M-token context, seven levels of thinking effort, tool calling and streaming over an OpenAI-compatible chat endpoint. ## Overview - **Endpoint**: `https://queue.modelrunner.run/z-ai/glm-5.2` - **Model ID**: `z-ai/glm-5.2` - **Category**: text-to-text - **Kind**: inference - **Tags**: glm, glm-5.2, z-ai, zhipu, llm, text-to-text, chat, chat-completions, openai-compatible, reasoning, thinking, agentic, agentic-coding, coding, code-generation, long-context, open-weight, open-source, mit-license, streaming, tool-calling, json-mode ## Pricing - **Input tokens**: $1.4 per 1M - **Cached input tokens**: $0.35 per 1M - **Output tokens**: $4.4 per 1M ## Request Lifecycle This model runs on the ModelRunner **asynchronous queue API** — a single POST does not return the output. Every call requires an `Authorization: Key $MODEL_RUNNER_KEY` header. Run three steps: 1. **Submit** — `POST https://queue.modelrunner.run/z-ai/glm-5.2` with a JSON body holding the input fields at the top level. The body may also include a reserved top-level `metadata` object — a flat string map (max 16 keys, key ≤64 / value ≤512 chars) stored on the request for your own tagging. It is never sent to the model; filter your request history with `GET https://queue.modelrunner.run/requests?metadata=` (exact key=value matches, AND-ed). The response carries request handles only (no output yet): ```json { "status": "IN_QUEUE", "request_id": "<21-char id>", "status_url": "https://queue.modelrunner.run/z-ai/glm-5.2/requests//status", "response_url": "https://queue.modelrunner.run/z-ai/glm-5.2/requests/", "cancel_url": "https://queue.modelrunner.run/z-ai/glm-5.2/requests//cancel" } ``` 2. **Poll status** — `GET ` until `status` is `COMPLETED`. Possible values are `IN_QUEUE`, `IN_PROGRESS`, `COMPLETED`, `FAILED`, `CANCELLED`. A `FAILED` request responds with HTTP 400 and an `error` field. 3. **Read result** — `GET `. Returns the finished request, including the generated `output`: ```json { "id": "", "status": "COMPLETED", "output": ..., "input": ... } ``` The JavaScript and Python SDKs below perform steps 2–3 for you. In any language without an SDK (Swift, Go, Kotlin, etc.) you must implement the polling loop and the final result fetch yourself — see the cURL example for the full flow. ### Input Schema - **`seed`** (`integer`, _optional_): Best-effort determinism hint. - **`stop`** (`unknown`, _optional_): Up to 4 stop sequences. - **`tools`** (`array`, _optional_): OpenAI-format tool definitions the model may call. - **`stream`** (`boolean`, _optional_): Return the reply as a Server-Sent Events stream of deltas terminated by \`data: \[DONE\]\`. - Default: `false` - **`messages`** (`array`, _required_): OpenAI-style conversation history. Each item is an object with a \`role\` (\`system\`, \`user\`, \`assistant\` or \`tool\`) and \`content\`. - **`max_tokens`** (`integer`, _optional_): Upper bound on generated tokens, up to the documented 131,072-token output ceiling. Thinking consumes this budget, so allow generous headroom. - Range: `1` to `"+inf"` - **`tool_choice`** (`unknown`, _optional_): \`auto\`, \`none\`, \`required\`, or a specific tool. - **`response_format`** (`object`, _optional_): Structured-output control. Set its \`type\` to \`json_object\` to force a JSON reply. - **`reasoning_effort`** (`ReasoningEffortEnum`, _optional_): How hard the model thinks before answering, across seven levels. Defaults to \`max\`, the highest — lower it to cut cost, because thinking tokens bill as output tokens. \`none\` disables reasoning entirely. - Default: `"max"` - Options: `"none"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, `"max"` ### Output Schema - **`id`** (`string`, _optional_): - **`model`** (`string`, _optional_): - **`usage`** (`object`, _optional_): - **`object`** (`string`, _optional_): - **`choices`** (`array`, _optional_): - **`created`** (`integer`, _optional_): ## Default Example **Input** ```json { "model": "z-ai/glm-5.2", "messages": [ { "role": "user", "content": "Find every bug in this function, explain each one, then give a corrected version with its time and space complexity.\n\ndef merge_intervals(intervals):\n intervals.sort()\n merged = [intervals[0]]\n for start, end in intervals[1:]:\n if start < merged[-1][1]:\n merged[-1][1] = end\n else:\n merged.append([start, end])\n return merged" } ], "max_tokens": 8000, "reasoning_effort": "high" } ``` **Output** ```json { "id": "chatcmpl-zWnLmsPZNMKRTeXzRVuob", "model": "z-ai/glm-5.2", "usage": { "total_tokens": 2208, "prompt_tokens": 98, "completion_tokens": 2110, "prompt_tokens_details": { "cached_tokens": 0 }, "completion_tokens_details": { "reasoning_tokens": 1577 } }, "object": "chat.completion", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The function `merge_intervals` contains several bugs. Here’s a breakdown:\n\n### 1. **No handling of empty input**\nIf `intervals` is an empty list, `merged = [intervals[0]]` raises an `IndexError`.\n\n### 2. **Incorrect overlap condition**\nThe condition `if start < merged[-1][1]` only checks if the current interval’s start is strictly less than the last merged interval’s end. \n- It misses intervals that just touch (e.g., `[1,2]` and `[2,3]`) when the problem expects them to be merged. \n- Even if changed to `<=`, the logic only sets `merged[-1][1] = end`, which **shrinks** the merged interval when the current end is smaller than the existing one (e.g., `[1,5]` and `[2,3]` would become `[1,3]` instead of staying `[1,5]`). The correct update is `merged[-1][1] = max(merged[-1][1], end)`.\n\n### 3. **Mutates the input list in-place**\n`intervals.sort()` reorders the original list. Callers may not expect their input to be modified.\n\n### 4. **Aliases and modifies the original interval objects**\n`merged = [intervals[0]]` stores a reference to the very first interval object (after sorting). When the code does `merged[-1][1] = end`, it directly changes the original interval’s end value. This is a side effect that can corrupt the caller’s data.\n\n---\n\n## Corrected Version\n\n```python\ndef merge_intervals(intervals):\n if not intervals:\n return []\n \n # Work on a sorted copy to avoid mutating the input\n sorted_intervals = sorted(intervals, key=lambda x: x[0])\n \n # Copy the first interval so we don't modify the original\n merged = [list(sorted_intervals[0])]\n \n for start, end in sorted_intervals[1:]:\n last = merged[-1]\n if start <= last[1]: # overlapping or touching\n last[1] = max(last[1], end) # extend only if needed\n else:\n merged.append([start, end])\n \n return merged\n```\n\n### Complexity\n- **Time:** O(n log n) due to sorting (n = number of intervals). The subsequent loop is O(n). \n- **Space:** O(n) for the sorted copy and the output list of merged intervals.", "reasoning_content": "We need to find every bug in the function merge_intervals, explain each, then give a corrected version with time and space complexity.\n\nThe function is:\ndef merge_intervals(intervals):\n intervals.sort()\n merged = [intervals[0]]\n for start, end in intervals[1:]:\n if start < merged[-1][1]:\n merged[-1][1] = end\n else:\n merged.append([start, end])\n return merged\n\nAssumptions: intervals is a list of intervals, each interval is a list of two numbers [start, end], probably representing start and end of interval, where start <= end? Usually intervals are [start, end] with start < end, but maybe not sorted. The typical problem: given a list of intervals (e.g., [1,3], [2,6], [8,10], [15,18]), merge overlapping intervals, return merged intervals.\n\nBugs:\n1. Accessing intervals[0] when intervals might be empty. If intervals is empty, intervals[0] will raise IndexError. Should handle empty input.\n2. The merge logic: if start < merged[-1][1]: This only checks if the current interval's start is less than the last merged interval's end. But what if the current interval's end is less than the merged's end? The current interval might be completely inside the last merged interval. The condition should be if start <= merged[-1][1] (or start < merged[-1][1] but if start == merged[-1][1] they are overlapping? In interval merging, intervals [1,3] and [3,5] are considered overlapping? Usually if they touch at endpoints, they might be merged or not. The problem statement usually says merge overlapping intervals. Some problems define overlapping as start <= end of previous. If start == previous end, they are contiguous, not overlapping? The standard LeetCode \"Merge Intervals\" problem defines overlapping if start <= previous end. But the bug here is that they only update the end to `end`, not taking the max of merged[-1][1] and end. If current interval is [2,4] and merged[-1] is [1,5], start=2 < 5, so they set merged[-1][1] = 4, which shrinks the interval incorrectly! They should set merged[-1][1] = max(merged[-1][1], end). So the condition is also insufficient: they should update the end to the max of the current end and the last merged end.\n3. The condition `if start < merged[-1][1]` is wrong for the case where intervals are just touching. If the problem expects merging contiguous intervals, the condition should be `<=`. But the main bug is not taking max.\n4. The function doesn't handle the case where the input list might not be sorted by start? They do intervals.sort() which sorts by the first element, then second element if tie. That's fine. But note: if intervals contain tuples or lists, sorting works. But what if the intervals are given as tuples? Then they try to assign merged[-1][1] = end, which would fail if intervals are tuples (immutable). The function assumes intervals are lists of lists. But the problem statement doesn't specify; we can mention that if intervals are tuples, it will crash. But that's a design issue, not a bug per se. Usually we assume mutable lists.\n5. Another bug: The function modifies the input intervals? It does intervals.sort() which sorts in place, modifying the original list. This may be unwanted side effect. Could use sorted(intervals) to avoid mutation.\n6. Edge case: intervals with same start? Sorting will sort by start then end. That's okay.\n7. The loop uses `for start, end in intervals[1:]`, which unpacks each interval. If an interval has more than two elements, it would fail. Assume intervals are pairs.\n8. The merged list is initialized with `merged = [intervals[0]]`. If intervals[0] is a list, merged[0] is a reference to the same list object. Then when they do `merged[-1][1] = end`, they modify the original interval's end! This is a bug if the caller doesn't expect the original intervals to be mutated. Because merged[-1] is the same list object as intervals[0] (since intervals.sort() modifies in place, intervals[0] is the original first interval object after sorting). They should create a copy, e.g., `merged = [list(intervals[0])]` or `merged = [intervals[0][:]]`.\n\nLet's list all bugs:\n- No empty list check (IndexError).\n- Incorrect merge condition: only updates end to current end, not max.\n- May incorrectly shrink intervals if current end is smaller.\n- Condition `start < merged[-1][1]` might not handle equality (if intervals touching should merge, but depends on problem). Typically `start <= merged[-1][1]`.\n- Mutates original intervals: `intervals.sort()` sorts in place, and `merged = [intervals[0]]` references the original list, then modifies `merged[-1][1]` which mutates the original interval. Need to copy.\n- (Potential) If intervals are tuples, assignment fails.\n\nExplain each:\n1. Empty input: If intervals is empty, `merged = [intervals[0]]` raises IndexError.\n2. Overlap condition: `if start < merged[-1][1]` only checks if start is less than end. But to merge, we need `start <= merged[-1][1]` (assuming touching intervals are merged). Even with that, setting `merged[-1][1] = end` is wrong because the merged interval should span from the original start to the maximum of the two ends. For example, intervals = [[1,5], [2,3]]. After sort, merged = [[1,5]], then current = [2,3], start=2 < 5, so it sets end to 3, resulting in [1,3] which is incorrect. Should be `merged[-1][1] = max(merged[-1][1], end)`.\n3. Side effect: `intervals.sort()` modifies the input list. Better to use `intervals = sorted(intervals)` or copy.\n4. Mutation of original intervals: `merged = [intervals[0]]` stores a reference to the original interval list. Then `merged[-1][1] = ...` modifies that original interval. To avoid, use a copy like `merged = [intervals[0][:]]` or `list(intervals[0])`.\n5. (If we consider tuple input) If intervals are tuples, `merged[-1][1] = end` fails because tuples are immutable. But the function signature doesn't specify, it's a bug if someone passes tuples. But typically intervals are lists. We can mention it as a robustness issue.\n\nTime and space complexity of corrected version:\n- Time: O(n log n) due to sorting, where n is number of intervals. The merge loop is O(n). Overall O(n log n).\n- Space: O(n) for the sorted list (if we create a copy) and the merged output. If we sort in place, O(1) extra space except output, but better to avoid mutation. Typically O(n) space for output and sorted copy.\n\nNow write the answer: list bugs, explanations, corrected version, complexity." }, "finish_reason": "stop" } ], "created": 1787043417 } ``` ## Usage Examples ### cURL The queue API is asynchronous: submit the request, poll `status_url` until it is `COMPLETED`, then read the result from `response_url`. Requires `jq`. ```bash # 1. Submit the request (returns request handles, not the output) SUBMIT=$(curl --silent --request POST \ --url https://queue.modelrunner.run/z-ai/glm-5.2 \ --header "Authorization: Key $MODEL_RUNNER_KEY" \ --header "Content-Type: application/json" \ --data '{ "model": "z-ai/glm-5.2", "messages": [ { "role": "user", "content": "Find every bug in this function, explain each one, then give a corrected version with its time and space complexity.\n\ndef merge_intervals(intervals):\n intervals.sort()\n merged = [intervals[0]]\n for start, end in intervals[1:]:\n if start < merged[-1][1]:\n merged[-1][1] = end\n else:\n merged.append([start, end])\n return merged" } ], "max_tokens": 8000, "reasoning_effort": "high" }') STATUS_URL=$(echo "$SUBMIT" | jq -r '.status_url') RESPONSE_URL=$(echo "$SUBMIT" | jq -r '.response_url') # 2. Poll until the request leaves the queue / in-progress state while true; do STATUS=$(curl --silent --url "$STATUS_URL" \ --header "Authorization: Key $MODEL_RUNNER_KEY" | jq -r '.status') echo "Status: $STATUS" case "$STATUS" in COMPLETED) break ;; FAILED|CANCELLED) echo "Request $STATUS"; exit 1 ;; esac sleep 1 done # 3. Read the finished request, including the generated output curl --silent --url "$RESPONSE_URL" \ --header "Authorization: Key $MODEL_RUNNER_KEY" ``` ### JavaScript ```javascript import { modelrunner } from "@modelrunner/client"; const result = await modelrunner.subscribe("z-ai/glm-5.2", { input: { "model": "z-ai/glm-5.2", "messages": [ { "role": "user", "content": "Find every bug in this function, explain each one, then give a corrected version with its time and space complexity.\n\ndef merge_intervals(intervals):\n intervals.sort()\n merged = [intervals[0]]\n for start, end in intervals[1:]:\n if start < merged[-1][1]:\n merged[-1][1] = end\n else:\n merged.append([start, end])\n return merged" } ], "max_tokens": 8000, "reasoning_effort": "high" } }); console.log(result.data); ``` ### Python ```python import asyncio import modelrunner_ai async def main(): response = await modelrunner_ai.submit_async( "z-ai/glm-5.2", arguments={ "model": "z-ai/glm-5.2", "messages": [ { "role": "user", "content": "Find every bug in this function, explain each one, then give a corrected version with its time and space complexity.\n\ndef merge_intervals(intervals):\n intervals.sort()\n merged = [intervals[0]]\n for start, end in intervals[1:]:\n if start < merged[-1][1]:\n merged[-1][1] = end\n else:\n merged.append([start, end])\n return merged" } ], "max_tokens": 8000, "reasoning_effort": "high" } ) result = await response.get() print(result["output"]) asyncio.run(main()) ``` ## Additional Resources - [Playground](https://modelrunner.ai/models/z-ai/glm-5.2) - [OpenAPI Schema](https://modelrunner.ai/models/z-ai/glm-5.2/openapi.json) - [LLM Instructions](https://modelrunner.ai/models/z-ai/glm-5.2/llms.txt) - [GitHub](https://github.com/zai-org/GLM-5) - [License](https://huggingface.co/zai-org/GLM-5.2/blob/main/README.md) - [Weights](https://huggingface.co/zai-org/GLM-5.2) - [Paper](https://arxiv.org/abs/2602.15763)