Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 158 additions & 25 deletions backend/agents/create_agent_info.py

Large diffs are not rendered by default.

348 changes: 336 additions & 12 deletions backend/apps/model_managment_app.py

Large diffs are not rendered by default.

75 changes: 75 additions & 0 deletions backend/apps/monitoring_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,68 @@
return []


def _query_context_budget_metrics_from_db(

Check failure on line 116 in backend/apps/monitoring_app.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 22 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=ModelEngine-Group_nexent&issues=AaAy1jYQT795FaYgHZNn&open=AaAy1jYQT795FaYgHZNn&pullRequest=3759
time_range: str, tenant_id: str | None = None
) -> list[dict[str, Any]]:
"""Aggregate content-free P3 evidence by Provider/model/profile version."""
time_filter = _compute_time_range_filter(time_range)
tenant_filter = "AND m.tenant_id = :tenant_id" if tenant_id else ""
params = {"tenant_id": tenant_id} if tenant_id else {}
query_sql = f"""
SELECT
COALESCE(m.context_budget_evidence->>'provider_protocol', 'unknown') AS provider_protocol,
m.model_name,
COALESCE(m.capability_profile_version, 'unknown') AS capability_profile_version,
COUNT(*) FILTER (WHERE m.context_budget_evidence IS NOT NULL) AS request_count,
COUNT(*) FILTER (WHERE COALESCE((m.context_budget_evidence->>'provider_overflow')::boolean, FALSE)) AS overflow_count,
COUNT(*) FILTER (WHERE COALESCE((m.context_budget_evidence->>'compression_attempted')::boolean, FALSE)) AS compacted_count,
ROUND(AVG(CASE WHEN COALESCE((m.context_budget_evidence->>'compression_attempted')::boolean, FALSE)
AND (m.context_budget_evidence->>'context_raw_tokens')::numeric > 0
THEN 1 - (m.context_budget_evidence->>'context_final_tokens')::numeric
/ (m.context_budget_evidence->>'context_raw_tokens')::numeric END), 4) AS avg_compression_ratio,
COUNT(*) FILTER (WHERE (m.context_budget_evidence->>'provider_prompt_usage_tokens')::numeric > 0) AS estimate_sample_count,
ROUND(AVG(CASE WHEN (m.context_budget_evidence->>'provider_prompt_usage_tokens')::numeric > 0
THEN ABS((m.context_budget_evidence->>'raw_estimate_tokens')::numeric
- (m.context_budget_evidence->>'provider_prompt_usage_tokens')::numeric)
/ (m.context_budget_evidence->>'provider_prompt_usage_tokens')::numeric END), 4) AS mean_absolute_estimate_error,
COUNT(*) FILTER (WHERE COALESCE((m.context_budget_evidence->>'recovery_attempted')::boolean, FALSE)) AS recovery_attempt_count,
COUNT(*) FILTER (WHERE COALESCE((m.context_budget_evidence->>'recovery_succeeded')::boolean, FALSE)) AS recovery_success_count
FROM nexent.model_monitoring_record_t m
WHERE {time_filter} {tenant_filter} AND m.delete_flag = 'N'
AND m.context_budget_evidence IS NOT NULL
GROUP BY provider_protocol, m.model_name, capability_profile_version
ORDER BY request_count DESC
"""
try:
with get_monitoring_db_session() as session:
rows = session.execute(text(query_sql), params).fetchall()
output = []
for row in rows:
requests = int(row.request_count or 0)
attempts = int(row.recovery_attempt_count or 0)
compacted = int(row.compacted_count or 0)
output.append({
"provider_protocol": row.provider_protocol,
"model_name": row.model_name,
"capability_profile_version": row.capability_profile_version,
"request_count": requests,
"overflow_count": int(row.overflow_count or 0),
"overflow_rate": (int(row.overflow_count or 0) / requests) if requests else None,
"compacted_count": compacted,
"compaction_incidence": (compacted / requests) if requests else None,
"avg_compression_ratio": float(row.avg_compression_ratio) if row.avg_compression_ratio is not None else None,
"estimate_sample_count": int(row.estimate_sample_count or 0),
"mean_absolute_estimate_error": float(row.mean_absolute_estimate_error) if row.mean_absolute_estimate_error is not None else None,
"recovery_attempt_count": attempts,
"recovery_success_count": int(row.recovery_success_count or 0),
"recovery_success_rate": (int(row.recovery_success_count or 0) / attempts) if attempts else None,
})
return output
except Exception as exc:
logger.error("Failed to query context budget metrics: %s", exc)
return []


@router.get("/models", response_model=ConversationResponse)
async def list_models_endpoint(
time_range: Annotated[str, Query(
Expand Down Expand Up @@ -147,3 +209,16 @@
message="success",
data=get_monitoring_status(),
)


@router.get("/context-budget", response_model=ConversationResponse)
async def get_context_budget_metrics_endpoint(
time_range: Annotated[str, Query(description="Time range: 24h, 7d, 30d")] = "24h",
authorization: Annotated[str | None, Header()] = None,
):
_, tenant_id = get_current_user_id(authorization)
return ConversationResponse(
code=0,
message="success",
data=_query_context_budget_metrics_from_db(time_range, tenant_id),
)
55 changes: 53 additions & 2 deletions backend/consts/capability_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
logger = logging.getLogger(__name__)


CATALOG_REVISION = "2026-06-27.1"
CATALOG_REVISION = "2026-08-24.2"


CATALOG: Dict[ProfileKey, CapabilityProfile] = {
Expand Down Expand Up @@ -55,6 +55,16 @@
max_output_tokens=16_384,
default_output_reserve_tokens=4_096,
tokenizer_family="qwen",
aliases=("qwen-plus",),
exclusions=("qwen-vl", "qwen-omni"),
evidence=("aliyun-model-studio-model-catalog-2026-08",),
verified_at="2026-08-01T00:00:00Z",
shared_context=True,
independent_input=False,
max_output=16_384,
reasoning_behavior="unknown",
overhead_behavior="bounded",
confidence="high",
),
("dashscope", "qwen-turbo"): CapabilityProfile(
provider="dashscope",
Expand All @@ -66,6 +76,29 @@
default_output_reserve_tokens=4_096,
tokenizer_family="qwen",
),
# Verified 2026-08-24 against the official model-specific DashScope page:
# https://help.aliyun.com/zh/model-studio/qwen3-7-plus
("dashscope", "qwen3.7-plus"): CapabilityProfile(
provider="dashscope",
model_name="qwen3.7-plus",
capability_profile_version="dashscope/qwen3.7-plus@1",
window_shape="combined",
context_window_tokens=1_000_000,
max_input_tokens=991_808,
max_output_tokens=131_072,
default_output_reserve_tokens=8_192,
tokenizer_family="qwen",
aliases=("qwen3.7-plus", "qwen-3.7-plus"),
exclusions=("qwen3.7-max", "qwen3.7-flash"),
evidence=("https://help.aliyun.com/zh/model-studio/qwen3-7-plus",),
verified_at="2026-08-24T00:00:00Z",
shared_context=True,
independent_input=False,
max_output=131_072,
reasoning_behavior="reserved",
overhead_behavior="bounded",
confidence="high",
),
# Sources cross-checked 2026-06-23:
# https://help.aliyun.com/zh/model-studio/models (Bailian model catalog)
# https://llm-stats.com/models/qwen3.7-max (1.0M input, 65.5K output)
Expand All @@ -89,15 +122,33 @@
default_output_reserve_tokens=8_192,
tokenizer_family="chatglm",
),
# Verified 2026-08-24 against SiliconFlow's model center and launch note.
# The list-models API exposes identity only, so this complete catalog row is
# the capacity fallback for the hosted model.
# https://www.siliconflow.cn/models
# https://www.siliconflow.cn/news/grz0d71bw8xguh4n6lnjqkw9
("silicon", "Qwen/Qwen3.6-27B"): CapabilityProfile(

Check failure on line 130 in backend/consts/capability_profiles.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "Qwen/Qwen3.6-27B" 3 times.

See more on https://sonarcloud.io/project/issues?id=ModelEngine-Group_nexent&issues=AaAzroI9yvQ8CG26o_Et&open=AaAzroI9yvQ8CG26o_Et&pullRequest=3759
provider="silicon",
model_name="Qwen/Qwen3.6-27B",
capability_profile_version="silicon/qwen3.6-27b@1",
capability_profile_version="silicon/qwen3.6-27b@2",
window_shape="combined",
context_window_tokens=262_144,
max_output_tokens=65_536,
default_output_reserve_tokens=8_192,
tokenizer_family="qwen",
aliases=("Qwen/Qwen3.6-27B", "Qwen3.6-27B"),
exclusions=("Qwen3.6-35B-A3B",),
evidence=(
"https://www.siliconflow.cn/models",
"https://www.siliconflow.cn/news/grz0d71bw8xguh4n6lnjqkw9",
),
verified_at="2026-08-24T00:00:00Z",
shared_context=True,
independent_input=False,
max_output=65_536,
reasoning_behavior="reserved",
overhead_behavior="bounded",
confidence="high",
),
("silicon", "Pro/moonshotai/Kimi-K2.6"): CapabilityProfile(
provider="silicon",
Expand Down
9 changes: 9 additions & 0 deletions backend/consts/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,15 @@ class ValidationError(Exception):
pass


class ModelCapacityConfigError(ValidationError, ValueError):
"""Raised when a model capacity contract is internally inconsistent."""

def __init__(self, reason_code: str, message: str, *, field: str = None):
self.reason_code = reason_code
self.field = field
super().__init__(f"{reason_code}: {message}")


class TenantResourceLimitError(ValidationError, ValueError):
"""Raised when a platform or tenant hard resource limit is reached."""

Expand Down
40 changes: 39 additions & 1 deletion backend/consts/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ class ModelRequest(BaseModel):
tokenizer_family: Optional[str] = None
capacity_source: Optional[str] = None
capability_profile_version: Optional[str] = None
feature_capability_metadata: Optional[Dict[str, Any]] = None
capacity_mode: Optional[Literal["auto", "manual"]] = None
# W11 accept-signal fields (audit/metrics only — never persisted). Sent by
# the frontend when the operator clicks "Use suggestion" and saves; the
# app layer pops them before the dict reaches the service/DB layer and
Expand Down Expand Up @@ -197,7 +199,11 @@ class ModelCapacitySuggestionResponse(BaseModel):
suggested_provider: Optional[str] = None
canonical_model_name: Optional[str] = None
capability_profile_version: Optional[str] = None
capacity_source_on_accept: Optional[Literal["operator"]] = None
capacity_source_on_accept: Optional[Literal["operator", "profile"]] = None
canonical_identity: Optional[Dict[str, Any]] = None
capacity_match: Optional[Dict[str, Any]] = None
tokenizer_match: Optional[Dict[str, Any]] = None
governance_metadata_proposal: Optional[Dict[str, Any]] = None


class CapacityCoverageBareModel(BaseModel):
Expand All @@ -215,6 +221,36 @@ class CapacityCoverageResponse(BaseModel):
bare_models: List[CapacityCoverageBareModel] = Field(default_factory=list)


class CapacityAdoptionPreviewRequest(BaseModel):
display_name: str = Field(..., min_length=1, max_length=256)
expected_matcher_version: Optional[str] = None


class CapacityAdoptRequest(BaseModel):
display_name: str = Field(..., min_length=1, max_length=256)
expected_profile_version: str = Field(..., min_length=1, max_length=256)
expected_matcher_version: Optional[str] = None
fields: Optional[List[str]] = None
reset_manual_fields: List[str] = Field(default_factory=list)


class TokenCountProbeRequest(BaseModel):
display_name: str = Field(..., min_length=1, max_length=256)
force: bool = False


class ManageCapacityAdoptionPreviewRequest(CapacityAdoptionPreviewRequest):
tenant_id: str = Field(..., min_length=1)


class ManageCapacityAdoptRequest(CapacityAdoptRequest):
tenant_id: str = Field(..., min_length=1)


class ManageTokenCountProbeRequest(TokenCountProbeRequest):
tenant_id: str = Field(..., min_length=1)


class ProviderModelRequest(BaseModel):
provider: str
model_type: str
Expand Down Expand Up @@ -1308,6 +1344,7 @@ class ManageTenantModelCreateRequest(BaseModel):
tokenizer_family: Optional[str] = Field(None, description="Token-counting strategy or tokenizer identifier")
capacity_source: Optional[str] = Field(None, description="Source of the persisted capacity value")
capability_profile_version: Optional[str] = Field(None, description="Version of the approved capability profile")
capacity_mode: Optional[Literal["auto", "manual"]] = Field(None, description="Capacity inheritance mode")
# W11 accept-signal fields. Same audit-only contract as ModelRequest:
# the app layer pops them off model_data before the dict reaches the
# service/DB layer and forwards them to
Expand Down Expand Up @@ -1347,6 +1384,7 @@ class ManageTenantModelUpdateRequest(BaseModel):
tokenizer_family: Optional[str] = Field(None, description="Token-counting strategy or tokenizer identifier")
capacity_source: Optional[str] = Field(None, description="Source of the persisted capacity value")
capability_profile_version: Optional[str] = Field(None, description="Version of the approved capability profile")
capacity_mode: Optional[Literal["auto", "manual"]] = Field(None, description="Capacity inheritance mode")
# W11 accept-signal fields. See ManageTenantModelCreateRequest for the
# contract. The app layer pops them before calling the service so
# update_model_record never sees them.
Expand Down
Loading