Skip to content

feat: add MiniMax LLM provider instrumentation (M2.7 default)#140

Open
octo-patch wants to merge 3 commits intofuture-agi:mainfrom
octo-patch:feature/add-minimax-provider
Open

feat: add MiniMax LLM provider instrumentation (M2.7 default)#140
octo-patch wants to merge 3 commits intofuture-agi:mainfrom
octo-patch:feature/add-minimax-provider

Conversation

@octo-patch
Copy link

@octo-patch octo-patch commented Mar 12, 2026

Summary

Add MiniMax as a supported LLM provider for traceAI instrumentation, with M2.7 as the default model.

Changes

  • Add MiniMax instrumentation package (traceai-minimax) with OpenTelemetry support
  • Support for MiniMax-M2.7 (default), MiniMax-M2.7-highspeed, MiniMax-M2.5, and MiniMax-M2.5-highspeed models
  • Automatic tracing of chat completions via OpenAI-compatible SDK
  • Streaming response support, function/tool calling support
  • Full test suite (21 tests passing)

Why

MiniMax-M2.7 is the latest flagship model with enhanced reasoning and coding capabilities. This instrumentation enables observability for MiniMax API calls through OpenTelemetry.

Testing

  • 21 unit tests passing
  • Tests cover request/response attribute extraction, streaming, tool calls, model detection
  • Default model (M2.7) verified in tests

@NVJKKartik NVJKKartik self-requested a review March 13, 2026 10:17
- Both international (api.minimax.io) and domestic (api.minimaxi.com) endpoints
"""

__slots__ = (
Copy link
Contributor

Choose a reason for hiding this comment

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

slots declares only 3 attributes, but line 105 and 112 assign self._original_protect. This will raise AttributeError at runtime when evaluations (Guardrailing) is utilized . Add "_original_protect" to slots. Or you can either drop the protect assignment, it is traced by other instrumentors

else:
self._original_protect = None

def _uninstrument(self, **kwargs: Any) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

same here uninstrument doesn't restore the wrapper. I would suggest to remove the protect wrapper itself

content = message.get("content", "")
if content:
yield SpanAttributes.OUTPUT_VALUE, content

Copy link
Contributor

Choose a reason for hiding this comment

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

Line 101 yields OUTPUT_VALUE with readable content, then line 104 unconditionally yields OUTPUT_VALUE again with the raw JSON dump. Since set_attribute overwrites, the human-readable content is silently lost.
Either remove line 104 or use a different attribute key for the raw output. ( I would suggest checking the Conventions)

"tool_calls": list(self._tool_calls.values()),
"finish_reason": self._finish_reason
}
yield SpanAttributes.OUTPUT_VALUE, safe_json_dumps(output_summary)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same issue here, The dual overwrite would lose the content which the function is trying to extract

MINIMAX_BASE_URLS = [
"api.minimax.io",
"api.minimaxi.com",
]
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider Using ENUMS for better accessability


if base_url is not None:
base_url_str = str(base_url).lower()
return any(url in base_url_str for url in MINIMAX_BASE_URLS)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not verified but if there are custom deployments allowed from minimax with custom domains then this can be utilized for sub string matching. If this isn't the case please consider using ENUMS and strict matching for safety purposes

Copy link
Contributor

@NVJKKartik NVJKKartik left a comment

Choose a reason for hiding this comment

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

Hey @octo-patch Thank you for Contributing to the repo. The minimax provider is a great addition. The implementation is clean and follows the existing patterns well, I have flagged a few issues on the specific lines. Please address them and I will be happy to approve and publish

Add OpenTelemetry instrumentation for MiniMax (https://www.minimax.io/),
which provides an OpenAI-compatible API. This integration supports:

- MiniMax-M2.5 and MiniMax-M2.5-highspeed models (204K context)
- Sync and async chat completions
- Streaming responses
- Function/tool calling
- Token usage tracking

The implementation follows the same pattern as the existing DeepSeek
integration, detecting MiniMax clients by their base_url
(api.minimax.io) and wrapping OpenAI SDK calls accordingly.

Changes:
- New package: python/frameworks/minimax/ (traceai_minimax)
- Added MINIMAX to FiLLMProviderValues enum
- Updated README.md with MiniMax in supported frameworks
- Includes comprehensive tests (19 passing) and usage examples
@octo-patch octo-patch force-pushed the feature/add-minimax-provider branch from ac507f6 to f91e16c Compare March 15, 2026 14:13
@octo-patch octo-patch changed the title feat: Add MiniMax provider instrumentation support feat: add MiniMax LLM provider instrumentation Mar 15, 2026
- Add MiniMax-M2.7 and MiniMax-M2.7-highspeed to model list
- Set MiniMax-M2.7 as default model
- Keep all previous models as alternatives
- Update related tests and documentation
@octo-patch octo-patch changed the title feat: add MiniMax LLM provider instrumentation feat: add MiniMax LLM provider instrumentation (M2.7 default) Mar 18, 2026
- Remove protect wrapper entirely from MiniMaxInstrumentor (traced by
  other instrumentors), resolving both the __slots__ mismatch and the
  missing uninstrument restore
- Fix dual OUTPUT_VALUE overwrite in both non-streaming and streaming
  response extractors by removing the unconditional raw JSON dump that
  silently overwrote human-readable content
- Replace string constants with MiniMaxBaseURL enum in _utils.py and
  switch from substring matching to strict hostname matching via
  urlparse for safety
- Clean up conftest.py to remove now-unnecessary protect/fi.evals mocks
@octo-patch
Copy link
Author

Thanks for the thorough review @NVJKKartik! All four issues have been addressed in the latest commit:

  1. __slots__ / protect wrapper — Removed the protect wrapper entirely from MiniMaxInstrumentor. As you noted, it's already traced by other instrumentors, so duplicating it here was unnecessary and caused both the __slots__ mismatch and the missing _uninstrument restore. Also cleaned up the related fi.evals / GuardrailProtectWrapper imports and test mocks.

  2. _uninstrument not restoring the wrapper — Resolved by removing the protect wrapper altogether (see above).

  3. Dual OUTPUT_VALUE overwrite — Removed the unconditional raw JSON dump lines in both _ChatCompletionResponseAttributesExtractor.get_extra_attributes() and _StreamingChatCompletionResponseExtractor.get_extra_attributes(). The human-readable content is now preserved as the sole OUTPUT_VALUE.

  4. ENUMs + strict matching — Replaced the MINIMAX_BASE_URLS string list with a MiniMaxBaseURL(str, Enum) class. Switched from substring matching (url in base_url_str) to strict hostname matching via urlparse(), so only exact hostname matches are accepted.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants