Skip to content

Python: feat: Add Astraflow (UCloud) AI provider connector#13908

Closed
ucloudnb666 wants to merge 12 commits intomicrosoft:mainfrom
ucloudnb666:feat/astraflow-1776820953
Closed

Python: feat: Add Astraflow (UCloud) AI provider connector#13908
ucloudnb666 wants to merge 12 commits intomicrosoft:mainfrom
ucloudnb666:feat/astraflow-1776820953

Conversation

@ucloudnb666
Copy link
Copy Markdown

Summary

This PR adds a new AI provider connector for Astraflow (by UCloud / 优刻得), an OpenAI-compatible AI model aggregation platform that supports 200+ models.

What's added

  • python/semantic_kernel/connectors/ai/astraflow/ — full connector package following the exact same structure as the existing nvidia connector:
    • Settings (AstraflowSettings) — reads ASTRAFLOW_API_KEY (global) or ASTRAFLOW_CN_API_KEY (China) from environment, with sensible defaults for both endpoints.
    • Prompt execution settings (AstraflowPromptExecutionSettings, AstraflowChatPromptExecutionSettings, AstraflowEmbeddingPromptExecutionSettings)
    • Handler (AstraflowHandler) — thin async wrapper around openai.AsyncOpenAI
    • Chat completion service (AstraflowChatCompletion)
    • Text embedding service (AstraflowTextEmbedding)
    • README with quick-start examples
  • .env.example — adds ASTRAFLOW_API_KEY and ASTRAFLOW_CN_API_KEY entries

Endpoints

Region Base URL Env var
Global (US/CA) https://api-us-ca.umodelverse.ai/v1 ASTRAFLOW_API_KEY
China https://api.modelverse.cn/v1 ASTRAFLOW_CN_API_KEY

Usage

from semantic_kernel.connectors.ai.astraflow import AstraflowChatCompletion, AstraflowTextEmbedding

# Chat completion (global endpoint, set ASTRAFLOW_API_KEY env var)
chat = AstraflowChatCompletion(ai_model_id="deepseek-ai/DeepSeek-V3")

# Text embedding
embed = AstraflowTextEmbedding(ai_model_id="BAAI/bge-m3")

# China endpoint
chat_cn = AstraflowChatCompletion(
    ai_model_id="deepseek-ai/DeepSeek-V3",
    base_url="https://api.modelverse.cn/v1",
    api_key="...",
)

Sign up at https://astraflow.ucloud.cn/

…astraflow/prompt_execution_settings/__init__.py
…astraflow/prompt_execution_settings/astraflow_prompt_execution_settings.py
…astraflow/services/astraflow_chat_completion.py
…astraflow/services/astraflow_text_embedding.py
@ucloudnb666 ucloudnb666 requested a review from a team as a code owner April 22, 2026 01:23
@moonbox3 moonbox3 added python Pull requests for the Python Semantic Kernel documentation labels Apr 22, 2026
@github-actions github-actions Bot changed the title feat: Add Astraflow (UCloud) AI provider connector Python: feat: Add Astraflow (UCloud) AI provider connector Apr 22, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 4 | Confidence: 93%

✗ Correctness

The Astraflow connector has one blocking bug: streaming chat completions will always crash with an AssertionError because the code asserts that the OpenAI AsyncStream response is an instance of collections.abc.AsyncGenerator, which it is not (verified: issubclass(AsyncStream, AsyncGenerator) is False). Additionally, the _prepare_chat_history_for_request method unnecessarily overrides the base class's robust implementation with a naive one that loses tool-call and structured content information.

✗ Security Reliability

The new Astraflow connector introduces three reliability concerns: (1) the custom _prepare_chat_history_for_request override bypasses ChatMessageContent.to_dict(), which strips tool_calls, tool_call_id, and multi-modal content from the request payload — breaking function/tool calling despite the connector explicitly implementing tool-call parsing; (2) AstraflowTextEmbedding.from_dict omits the base_url parameter, silently losing custom endpoint configuration (e.g. China endpoint) during deserialization; (3) the embedding service only warns when no API key is found instead of failing fast, deferring errors to runtime with confusing messages.

✗ Test Coverage

This PR adds a new Astraflow AI connector with chat completion, text embedding, prompt execution settings, a handler, and configuration settings — but includes zero unit tests. Every other AI connector in the project (Nvidia, Ollama, Mistral AI, Anthropic, Azure AI Inference, etc.) has a corresponding test directory under python/tests/unit/connectors/ai/ with tests covering initialization, settings validation, chat completion (mocked), text embedding (mocked), error handling, and serialization round-trips. The complete absence of tests for all new classes is a blocking gap in test coverage.

✗ Design Approach

The connector is a reasonable 'OpenAI-compatible with custom base_url' implementation that follows the existing NVIDIA connector pattern. The most critical design flaw is that _prepare_chat_history_for_request is overridden to use message.content (plain text only) instead of message.to_dict(), which the base class already provides correctly. This means any conversation involving function/tool calls will silently lose the tool_call_id and structured content from TOOL-role messages, breaking function calling entirely. A secondary issue is that the response_format field is declared in the settings class but explicitly excluded from prepare_settings_dict, making JSON mode and structured output silently non-functional.

Flagged Issues

  • _prepare_chat_history_for_request (lines 282-293 of astraflow_chat_completion.py) overrides the base class to build a simple {role, content} dict using message.content (plain text) instead of message.to_dict(). This drops tool_calls on assistant messages, tool_call_id on tool-result messages, multi-modal content items, message name, and ignores the instruction_role setting. Since the connector supports function calling (parses tool_calls in responses, exposes tools in settings), any multi-turn function-calling conversation will fail. The base class ChatCompletionClientBase._prepare_chat_history_for_request already handles OpenAI-compatible serialization correctly via message.to_dict(). The fix is to remove this override entirely.

Automated review by ucloudnb666's agents

@sphenry
Copy link
Copy Markdown
Member

sphenry commented Apr 22, 2026

@ucloudnb666 These connectors are better supported from from the Astraflow repo

@moonbox3 moonbox3 closed this Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants