Skip to content

fix(agents): parse MiniMax M2.5 XML tool calls instead of silently stripping#46401

Closed
Br1an67 wants to merge 1 commit into
openclaw:mainfrom
Br1an67:fix/41839
Closed

fix(agents): parse MiniMax M2.5 XML tool calls instead of silently stripping#46401
Br1an67 wants to merge 1 commit into
openclaw:mainfrom
Br1an67:fix/41839

Conversation

@Br1an67

@Br1an67 Br1an67 commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #41839 — MiniMax M2.5 tool calls were silently stripped from assistant messages instead of being dispatched as structured tool calls.

Problem

MiniMax M2.5 embeds tool invocations as XML in text content blocks instead of emitting standard toolUse blocks:

<minimax:tool_call>
<invoke name="Bash">
<parameter name="command">ls -la</parameter>
</invoke>
</minimax:tool_call>

The existing stripMinimaxToolCallXml() removed this XML from displayed text but never parsed or dispatched the tool calls — they were silently dropped.

Solution

New functions in pi-embedded-utils.ts:

  • parseMinimaxToolCallXml(text) — Extracts <invoke name="..."><parameter name="...">value</parameter></invoke> blocks from text containing minimax:tool_call markers. Returns an array of { name, input, id } objects with toolu_minimax_ prefixed IDs.

  • promoteMinimaxToolCallsToBlocks(message) — Transforms assistant message content in-place (same pattern as promoteThinkingTagsToBlocks): iterates text blocks, parses XML tool calls, strips the XML from remaining text, and inserts structured { type: "toolUse", id, name, input } content blocks.

Integration:

Called in pi-embedded-subscribe.handlers.messages.ts right after promoteThinkingTagsToBlocks() and before extractAssistantText(), ensuring tool calls are available as structured blocks before text sanitization runs.

Backward compatibility:

Falls back gracefully — if parsing yields no tool calls (e.g. <invoke> without name attribute), the text block is left untouched and the existing stripMinimaxToolCallXml() inside extractAssistantText() still cleans stray tags.

Test plan

  • 9 tests for parseMinimaxToolCallXml (empty input, single/multiple invocations, multiple params, extra attributes, missing name, unique IDs, special characters)
  • 8 tests for promoteMinimaxToolCallsToBlocks (basic conversion, tool-only text, multiple blocks, non-minimax blocks preserved, existing toolUse preserved, fallback on missing name, null content entries)
  • All 23 existing extractAssistantText tests continue to pass

Note

This PR was authored with assistance from GitHub Copilot.

@greptile-apps

greptile-apps Bot commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a long-standing silent data-loss bug: MiniMax M2.5 tool calls embedded as XML in text content blocks are now parsed into structured toolUse blocks and dispatched properly, instead of being stripped and discarded. The approach follows the established promoteThinkingTagsToBlocks pattern and integrates cleanly at the right point in the handleMessageEnd pipeline.

Key observations:

  • Integration placement is correctpromoteMinimaxToolCallsToBlocks is called before extractAssistantText, ensuring structured blocks are available before text sanitization runs and the fallback stripMinimaxToolCallXml inside extractAssistantText still handles any edge cases.
  • XML entity decoding is absent — the regex parser passes parameter values verbatim, so &amp;, &lt;, and similar entities would reach tool inputs in encoded form if MiniMax emits them. The test for special characters documents this as intentional but it could corrupt tool inputs in practice.
  • Prose ordering is not preserved across multiple tool calls — when multiple <invoke> blocks are interleaved with prose in a single text block, all prose is collapsed into one text block placed before all toolUse blocks. The original interleaved order is lost.
  • Module-level counter for ID generationminimaxToolCallCounter is shared across all invocations and test workers; using crypto.randomUUID() or a timestamp+random combination would be safer and avoid potential cross-worker collisions.
  • Test coverage is good — 17 new tests cover empty input, single/multiple invocations, fallback on missing name, null content entries, and preservation of existing blocks.

Confidence Score: 4/5

  • Safe to merge — the fix is net-positive and the fallback path ensures existing behavior is never degraded; the flagged concerns are style-level correctness improvements, not blockers.
  • The core logic is correct, follows existing patterns, and has solid test coverage. The deducted point is for the XML entity decoding gap: if MiniMax ever properly encodes entities in parameter values, tool inputs will silently receive malformed strings (e.g., &amp; instead of &). This isn't confirmed to happen today, but it's an unresolved assumption. The prose-ordering and counter concerns are minor and unlikely to surface in production.
  • src/agents/pi-embedded-utils.ts — specifically the entity decoding gap in parseMinimaxToolCallXml and the module-level counter.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 48-51

Comment:
**Missing XML entity decoding for parameter values**

The regex parser captures parameter content verbatim without decoding XML entities. Well-formed XML requires `&` to be encoded as `&amp;`, `<` as `&lt;`, `>` as `&gt;`, etc. If MiniMax M2.5 emits compliant XML, a command like `echo "hello & world"` would appear in the raw XML as `echo "hello &amp; world"`, and that encoded string would be forwarded to the tool unchanged.

The test at line 679 of the test file explicitly asserts this pass-through behavior — confirming the issue is known but not resolved. If MiniMax does encode entities (even partially), tool invocations with `&`, `<`, or `"` in parameter values will silently receive the wrong input.

Consider adding a minimal entity decode step:

```typescript
const HTML_ENTITIES: Record<string, string> = {
  "&amp;": "&",
  "&lt;": "<",
  "&gt;": ">",
  "&quot;": '"',
  "&apos;": "'",
};

function decodeXmlEntities(value: string): string {
  return value.replace(/&(?:amp|lt|gt|quot|apos);/gi, (entity) => HTML_ENTITIES[entity.toLowerCase()] ?? entity);
}
```

Then apply it when storing the parameter value:

```typescript
input[paramMatch[1]] = decodeXmlEntities(paramMatch[2]!);
```

If MiniMax is confirmed to never encode entities, document that assumption explicitly in the JSDoc so future maintainers don't have to rediscover it.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 109-123

Comment:
**Interleaved prose order is not preserved across multiple tool calls**

When a single text block contains prose _between_ multiple `<invoke>` blocks — e.g.:

```
Let me read the file.
<invoke name="Read">...</invoke></minimax:tool_call>
Now let me run the command.
<invoke name="Bash">...</invoke></minimax:tool_call>
```

`stripMinimaxToolCallXml` collapses all prose into a single string (`"Let me read the file.\nNow let me run the command."`), which is pushed as one text block _before_ all `toolUse` blocks. The interleaved ordering ("read → prose → bash") is lost; downstream consumers will see all prose up-front followed by both tool calls.

This matches how `promoteThinkingTagsToBlocks` works (it preserves order within a single text block), but it is different from what a streaming model would produce. If ordering matters for the tool-dispatch pipeline, the prose segments should be split and interleaved between the `toolUse` blocks. If it intentionally doesn't matter, a brief comment would help future readers.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 18

Comment:
**Module-level mutable counter shared across all tests and all runtime invocations**

`minimaxToolCallCounter` is a module-level variable. In a long-running process it is monotonically increasing, which guarantees uniqueness — but:

1. **Concurrent tests**: `vitest` can run test files in parallel worker threads. Each worker gets its own module instance so the counter resets per worker, meaning two workers can produce the same `toolu_minimax_1` ID for the same session/message. This won't cause test failures (tests only check uniqueness _within_ a call), but if IDs are stored and later correlated they could collide.
2. **Readability**: A counter makes IDs predictable/sequential, but `crypto.randomUUID()` (or even `Date.now() + Math.random()`) would make IDs truly unique without shared state.

Consider:
```typescript
id: `toolu_minimax_${Date.now()}_${Math.random().toString(36).slice(2)}`,
```
or using `crypto.randomUUID()` if available in the target runtime.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 81c1247

Comment on lines +48 to +51
const paramRe = /<parameter\s+name=["']([^"']+)["'][^>]*>([\s\S]*?)<\/parameter>/gi;
for (const paramMatch of body.matchAll(paramRe)) {
input[paramMatch[1]] = paramMatch[2]!;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing XML entity decoding for parameter values

The regex parser captures parameter content verbatim without decoding XML entities. Well-formed XML requires & to be encoded as &amp;, < as &lt;, > as &gt;, etc. If MiniMax M2.5 emits compliant XML, a command like echo "hello & world" would appear in the raw XML as echo "hello &amp; world", and that encoded string would be forwarded to the tool unchanged.

The test at line 679 of the test file explicitly asserts this pass-through behavior — confirming the issue is known but not resolved. If MiniMax does encode entities (even partially), tool invocations with &, <, or " in parameter values will silently receive the wrong input.

Consider adding a minimal entity decode step:

const HTML_ENTITIES: Record<string, string> = {
  "&amp;": "&",
  "&lt;": "<",
  "&gt;": ">",
  "&quot;": '"',
  "&apos;": "'",
};

function decodeXmlEntities(value: string): string {
  return value.replace(/&(?:amp|lt|gt|quot|apos);/gi, (entity) => HTML_ENTITIES[entity.toLowerCase()] ?? entity);
}

Then apply it when storing the parameter value:

input[paramMatch[1]] = decodeXmlEntities(paramMatch[2]!);

If MiniMax is confirmed to never encode entities, document that assumption explicitly in the JSDoc so future maintainers don't have to rediscover it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 48-51

Comment:
**Missing XML entity decoding for parameter values**

The regex parser captures parameter content verbatim without decoding XML entities. Well-formed XML requires `&` to be encoded as `&amp;`, `<` as `&lt;`, `>` as `&gt;`, etc. If MiniMax M2.5 emits compliant XML, a command like `echo "hello & world"` would appear in the raw XML as `echo "hello &amp; world"`, and that encoded string would be forwarded to the tool unchanged.

The test at line 679 of the test file explicitly asserts this pass-through behavior — confirming the issue is known but not resolved. If MiniMax does encode entities (even partially), tool invocations with `&`, `<`, or `"` in parameter values will silently receive the wrong input.

Consider adding a minimal entity decode step:

```typescript
const HTML_ENTITIES: Record<string, string> = {
  "&amp;": "&",
  "&lt;": "<",
  "&gt;": ">",
  "&quot;": '"',
  "&apos;": "'",
};

function decodeXmlEntities(value: string): string {
  return value.replace(/&(?:amp|lt|gt|quot|apos);/gi, (entity) => HTML_ENTITIES[entity.toLowerCase()] ?? entity);
}
```

Then apply it when storing the parameter value:

```typescript
input[paramMatch[1]] = decodeXmlEntities(paramMatch[2]!);
```

If MiniMax is confirmed to never encode entities, document that assumption explicitly in the JSDoc so future maintainers don't have to rediscover it.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread src/agents/pi-embedded-utils.ts Outdated
Comment on lines +109 to +123
// Strip XML from text and keep any remaining prose.
const cleaned = stripMinimaxToolCallXml(text).trim();
if (cleaned) {
next.push({ type: "text", text: cleaned });
}

// Insert structured toolUse blocks.
for (const tc of toolCalls) {
next.push({
type: "toolUse",
id: tc.id,
name: tc.name,
input: tc.input,
} as unknown as (typeof next)[number]);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interleaved prose order is not preserved across multiple tool calls

When a single text block contains prose between multiple <invoke> blocks — e.g.:

Let me read the file.
<invoke name="Read">...</invoke></minimax:tool_call>
Now let me run the command.
<invoke name="Bash">...</invoke></minimax:tool_call>

stripMinimaxToolCallXml collapses all prose into a single string ("Let me read the file.\nNow let me run the command."), which is pushed as one text block before all toolUse blocks. The interleaved ordering ("read → prose → bash") is lost; downstream consumers will see all prose up-front followed by both tool calls.

This matches how promoteThinkingTagsToBlocks works (it preserves order within a single text block), but it is different from what a streaming model would produce. If ordering matters for the tool-dispatch pipeline, the prose segments should be split and interleaved between the toolUse blocks. If it intentionally doesn't matter, a brief comment would help future readers.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 109-123

Comment:
**Interleaved prose order is not preserved across multiple tool calls**

When a single text block contains prose _between_ multiple `<invoke>` blocks — e.g.:

```
Let me read the file.
<invoke name="Read">...</invoke></minimax:tool_call>
Now let me run the command.
<invoke name="Bash">...</invoke></minimax:tool_call>
```

`stripMinimaxToolCallXml` collapses all prose into a single string (`"Let me read the file.\nNow let me run the command."`), which is pushed as one text block _before_ all `toolUse` blocks. The interleaved ordering ("read → prose → bash") is lost; downstream consumers will see all prose up-front followed by both tool calls.

This matches how `promoteThinkingTagsToBlocks` works (it preserves order within a single text block), but it is different from what a streaming model would produce. If ordering matters for the tool-dispatch pipeline, the prose segments should be split and interleaved between the `toolUse` blocks. If it intentionally doesn't matter, a brief comment would help future readers.

How can I resolve this? If you propose a fix, please make it concise.

id: string;
}

let minimaxToolCallCounter = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module-level mutable counter shared across all tests and all runtime invocations

minimaxToolCallCounter is a module-level variable. In a long-running process it is monotonically increasing, which guarantees uniqueness — but:

  1. Concurrent tests: vitest can run test files in parallel worker threads. Each worker gets its own module instance so the counter resets per worker, meaning two workers can produce the same toolu_minimax_1 ID for the same session/message. This won't cause test failures (tests only check uniqueness within a call), but if IDs are stored and later correlated they could collide.
  2. Readability: A counter makes IDs predictable/sequential, but crypto.randomUUID() (or even Date.now() + Math.random()) would make IDs truly unique without shared state.

Consider:

id: `toolu_minimax_${Date.now()}_${Math.random().toString(36).slice(2)}`,

or using crypto.randomUUID() if available in the target runtime.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-utils.ts
Line: 18

Comment:
**Module-level mutable counter shared across all tests and all runtime invocations**

`minimaxToolCallCounter` is a module-level variable. In a long-running process it is monotonically increasing, which guarantees uniqueness — but:

1. **Concurrent tests**: `vitest` can run test files in parallel worker threads. Each worker gets its own module instance so the counter resets per worker, meaning two workers can produce the same `toolu_minimax_1` ID for the same session/message. This won't cause test failures (tests only check uniqueness _within_ a call), but if IDs are stored and later correlated they could collide.
2. **Readability**: A counter makes IDs predictable/sequential, but `crypto.randomUUID()` (or even `Date.now() + Math.random()`) would make IDs truly unique without shared state.

Consider:
```typescript
id: `toolu_minimax_${Date.now()}_${Math.random().toString(36).slice(2)}`,
```
or using `crypto.randomUUID()` if available in the target runtime.

How can I resolve this? If you propose a fix, please make it concise.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81c1247c9a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/pi-embedded-utils.ts Outdated
Comment on lines +41 to +43
const invokeRe = /<invoke\s+name=["']([^"']+)["'][^>]*>([\s\S]*?)<\/invoke>/gi;

for (const match of text.matchAll(invokeRe)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scope invoke parsing to minimax tool_call segments

This regex parses every <invoke ...> in the entire text as soon as minimax:tool_call appears anywhere, so explanatory/code-sample XML can be promoted into executable toolUse blocks even when it is not an actual tool invocation. In practice, a reply that discusses MiniMax XML format (or echoes user-provided XML) can accidentally trigger real tool execution; parsing should be limited to explicit <minimax:tool_call>...</minimax:tool_call> sections (or another strict envelope) before promoting blocks.

Useful? React with 👍 / 👎.

Comment thread src/agents/pi-embedded-utils.ts Outdated
Comment on lines +49 to +50
for (const paramMatch of body.matchAll(paramRe)) {
input[paramMatch[1]] = paramMatch[2]!;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Decode XML entities before assigning tool parameters

Parameter values are copied verbatim from XML text, so escaped entities remain encoded in tool inputs (for example &amp; instead of &). If MiniMax emits valid XML escaping, tool arguments become semantically wrong (&&, <, > and similar tokens are corrupted), which can break command/tool behavior despite the call being otherwise parsed successfully.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2cfbd1714c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/pi-embedded-utils.ts Outdated

for (const invokeMatch of text.matchAll(invokeReWalk)) {
const matchStart = invokeMatch.index!;
const prose = text.slice(cursor, matchStart).replace(/<\/?minimax:tool_call>/gi, "").trim();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Strip non-dispatched <invoke> tags from emitted prose

Only <minimax:tool_call> wrappers are removed from prose, so when a text block contains at least one parseable <invoke name="..."> plus any other <invoke> fragment that is not promoted, that leftover XML is emitted as user-visible text. For example, Before<invoke>debug</invoke><minimax:tool_call><invoke name="Bash">...</invoke></minimax:tool_call> will keep <invoke>debug</invoke> after promotion, and extractAssistantText will no longer strip it because stripMinimaxToolCallXml is gated on minimax:tool_call being present. This is a regression from the previous strip-only path that removed all <invoke> blocks in MiniMax-tagged text.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81c1247c9a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -268,6 +269,7 @@ export function handleMessageEnd(
return;
}
promoteThinkingTagsToBlocks(assistantMessage);
promoteMinimaxToolCallsToBlocks(assistantMessage);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Parse MiniMax tool XML before turn completion

Calling promoteMinimaxToolCallsToBlocks only in handleMessageEnd means XML is converted after the assistant turn has already completed, so the newly created toolUse blocks are observational only and are not dispatched through the normal tool-execution path; on later turns this can be misread as dangling tool calls and repaired into synthetic missing toolResult errors during history sanitization. This triggers whenever MiniMax emits XML tool-call text, so promotion needs to happen in the pre-dispatch message path (or not emit toolUse blocks at this stage).

Useful? React with 👍 / 👎.

@Br1an67
Br1an67 force-pushed the fix/41839 branch 2 times, most recently from dd66e4c to 81c1247 Compare March 15, 2026 04:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd66e4cdd3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

* left untouched and the existing strip-only path in extractAssistantText
* will clean it up.
*/
export function promoteMinimaxToolCallsToBlocks(message: AssistantMessage): void {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wire MiniMax tool-call promotion into runtime message handling

This new promotion path is currently dead code: a repo-wide usage check only finds promoteMinimaxToolCallsToBlocks in this file and its tests, so assistant turns never run it in production. As a result, MiniMax XML tool calls are still just text and then get removed by the existing text sanitizer path, meaning the commit does not actually dispatch the tool calls it was meant to preserve.

Useful? React with 👍 / 👎.


const toolCalls: ParsedMinimaxToolCall[] = [];
// Only parse <invoke> blocks within <minimax:tool_call>...</minimax:tool_call> segments
const segmentRe = /<minimax:tool_call>([\s\S]*?)<\/minimax:tool_call>/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept MiniMax invocations without an opening tool_call tag

The parser only extracts <invoke> blocks from fully wrapped <minimax:tool_call>...</minimax:tool_call> segments, but this codebase’s MiniMax fixtures (including several in this same test file) commonly use ...<invoke ...></invoke></minimax:tool_call> without the opening tag. In that format parseMinimaxToolCallXml returns no tool calls, so promotion silently falls back and the invocation is stripped instead of executed.

Useful? React with 👍 / 👎.

…ripping

Add parseMinimaxToolCallXml() to extract structured tool call data from
MiniMax XML embedded in text content blocks. Add
promoteMinimaxToolCallsToBlocks() which transforms text blocks containing
MiniMax XML into proper toolUse content blocks on the assistant message,
following the same in-place mutation pattern as promoteThinkingTagsToBlocks.

The promotion runs before extractAssistantText() so tool calls are
dispatched as structured blocks rather than silently dropped. Falls back
to the existing strip-only behavior when parsing yields no results.

Fixes openclaw#41839

Co-authored-by: Copilot <[email protected]>
@Br1an67

Br1an67 commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

Closing to manage active PR count. Will reopen when slot is available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MiniMax M2.5 tool calls have no effect — XML tool invocations are stripped instead of executed

1 participant