Bug Description
When a model outputs a tool call with a large integer argument (e.g., a Discord channel ID like 1234567890123456789), the value silently loses precision during JSON parsing, resulting in a wrong value like 1234567890123456800.
This is because JSON.parse() converts numbers to JavaScript Number (IEEE 754 double), which only safely represents integers up to 2^53 - 1 (Number.MAX_SAFE_INTEGER = 9007199254740991). Discord snowflake IDs are 64-bit integers that regularly exceed this limit.
Reproduction
- Configure a cron job or subagent that sends a message to a Discord channel
- Use a local model (e.g.,
glm-4.7-flash-q6-k via llama-swap) that outputs the channel ID as a JSON number rather than a string
- The model generates the correct ID during streaming (visible in generation output), but the parsed tool call contains the wrong (rounded) value
Model output (correct):
{"action":"send","channel":"discord","target":1234567890123456789,"message":"..."}
Parsed result (wrong):
{"action":"send","channel":"discord","target":1234567890123456800,"message":"..."}
The last digits change due to float64 rounding.
Impact
- Discord messages fail with "Unknown Channel" because the rounded ID doesn't exist
- Affects any tool call argument containing a large integer (Discord IDs, Slack IDs, etc.)
- Models that output IDs as strings (e.g., Claude) are unaffected, but this is model-dependent behavior
- Local/open-source models are more likely to output bare numbers
Suggested Fix
The json-bigint package is already installed (node_modules/.pnpm/json-bigint@1.0.0). It could be used in the tool call argument parsing path to preserve large integers as strings.
Alternatively, a post-parse step could detect integers exceeding Number.MAX_SAFE_INTEGER and convert them to strings.
The relevant parsing happens in:
src/agents/ollama-stream.ts (lines ~262, ~271) — JSON.parse() on NDJSON response lines
- Any other provider stream parsers that handle OpenAI-compatible tool call responses
Workaround
Instruct the model to always quote large IDs as strings in tool call arguments. This works but is fragile and model-dependent.
Environment
- OpenClaw v2026.2.15
- Provider: local (llama-swap, OpenAI-compatible API)
- Model: glm-4.7-flash-q6-k
- Node.js v22.22.0
Bug Description
When a model outputs a tool call with a large integer argument (e.g., a Discord channel ID like
1234567890123456789), the value silently loses precision during JSON parsing, resulting in a wrong value like1234567890123456800.This is because
JSON.parse()converts numbers to JavaScriptNumber(IEEE 754 double), which only safely represents integers up to2^53 - 1(Number.MAX_SAFE_INTEGER = 9007199254740991). Discord snowflake IDs are 64-bit integers that regularly exceed this limit.Reproduction
glm-4.7-flash-q6-kvia llama-swap) that outputs the channel ID as a JSON number rather than a stringModel output (correct):
{"action":"send","channel":"discord","target":1234567890123456789,"message":"..."}Parsed result (wrong):
{"action":"send","channel":"discord","target":1234567890123456800,"message":"..."}The last digits change due to float64 rounding.
Impact
Suggested Fix
The
json-bigintpackage is already installed (node_modules/.pnpm/json-bigint@1.0.0). It could be used in the tool call argument parsing path to preserve large integers as strings.Alternatively, a post-parse step could detect integers exceeding
Number.MAX_SAFE_INTEGERand convert them to strings.The relevant parsing happens in:
src/agents/ollama-stream.ts(lines ~262, ~271) —JSON.parse()on NDJSON response linesWorkaround
Instruct the model to always quote large IDs as strings in tool call arguments. This works but is fragile and model-dependent.
Environment