Skip to content

Feat hzw 20260810 - #3920

Merged
jeffwu-1999 merged 29 commits into
developfrom
feat_hzw_20260810
Sep 15, 2026
Merged

jeffwu-1999 merged 29 commits into
developfrom
feat_hzw_20260810

Conversation

@lijiayang619

Copy link
Copy Markdown
Contributor

模型配置修改

hzw110204 and others added 12 commits August 6, 2026 16:27
…erence params) + integrate develop features (allow_chat_metadata/vlm4/useModelList/dreaming/etc)
- ModelAddDialogV2: add model prop for edit mode (prefill custom form from existing model, default to 自定义接入 tab, call updateSingleModel/updateManageTenantModel on submit instead of add)
- modelConfig.tsx: handleCardEdit now renders ModelAddDialogV2 with model prop instead of ModelEditDialogV2
…e inference fixes

Capacity suggestion (catalog -> bundled LiteLLM JSON -> default):
- model_capacity_suggestion_service: remove LLM self-report fallback (dead code,
  providers without web search always return null); add _litellm_lookup reading
  the bundled LiteLLM model_prices_and_context_window.json (3818 models) as the
  second source; match by provider/name and bare-name final segment, preferring
  entries with both max_input and max_output
- main Dockerfile: bundle LiteLLM JSON at build time (works offline / no VPN)
- suggest_capacity: try LiteLLM bare-name match even when provider is
  uninferable (base_url still empty while typing)

Model add/edit dialog (V2):
- custom tab: debounced auto-lookup on model name (500ms) fills empty capacity
  fields only; configured tag reflects lookup result, not display_name presence
- connectivity probe no longer mutates capacity fields; probe carries
  temperature/top_p/extra_params so invalid __custom__ params surface at verify
  time as a 400 instead of failing at runtime
- __custom__ numeric strings coerce to numbers (top_k=50, not 50); fix
  .trim crash on numeric values in edit mode
- batch tab: add client-side model name search filter; per-row connectivity
  fills capacity from suggestion
- edit mode: onConnectivityChange reports probe result back to the model list
  so connect_status refreshes in place

Model config list:
- verifyModels now probes ALL models in the list (was: default-model selection
  only), updating rows in parallel
- remove misleading provider model-count badge; fix ModelConnectStatus
  duplicate declaration; drop unused DEFAULT_* imports

Type inference (_infer_model_type_from_name):
- match full name AND final path segment so repo-prefixed ids from aggregators
  (BAAI/bge-m3, Pro/..., deepseek-ai/...) classify correctly
- add contains-based rules aligned with develop TokenPony classifier:
  embedding/rerank/stt/tts mid-name, vlm3 (omni/video), vlm2 (image-gen
  keywords), vlm (vision/visual/ocr/vl-segment)

Connectivity service:
- port develop _embedding_url_candidates multi-candidate probe (normalized
  /embeddings URL first, then as-given) for embedding/multi_embedding
- _config_to_context: __custom__ KV pairs flow into extra_body at runtime
- openai_llm check_connectivity probe carries inference params

Type fixes: AgentDraft includes model_params_override; ModelEditDialogV2
keyMap adds vlm4; agent-prompt model override config dialog typing
# Conflicts:
#	backend/consts/const.py
#	backend/services/model_health_service.py
#	frontend/public/locales/en/common.json
#	frontend/public/locales/zh/common.json
The batch-import connectivity probe passed the bare provider root
(e.g. https://api.siliconflow.cn/v1/) straight to the rerank adapter,
which POSTs the URL as-is -> 404 -> unavailable even though the model
is fine. prepare_model_dict already appends /rerank when SAVING the
model, so probe-time and save-time URLs disagreed.

Mirror that munging in _perform_connectivity_check: dashscope roots get
the api/v1 .../services/rerank/text-rerank/text-rerank path, others get
{root}/rerank. Already-normalized URLs pass through untouched. This
matches the embedding probe /embeddings normalization.
Batch submit requires every enabled row to pass the connectivity probe
(hasUnchecked gate), but the verified available result lived only in
dialog state — the create endpoints never received it, so the backend
reset connect_status to not_detected on insert and the freshly imported
models showed as unverified in the list.

The backend already honors this (create_model_for_tenant:
connect_status = payload or NOT_DETECTED; ModelRequest has the field) —
only the frontend was not sending it. Thread connectStatus through
addCustomModel / createManageTenantModel request bodies and set it from
the row state at batch submit time.
The button opened a 2000-line legacy panel whose single-row edit/delete
duplicated the per-row actions (and used the old V1 edit dialog), and
whose only unique capability was a narrow bulk-edit (same-provider key,
timeout, capacity override). Bulk delete did not exist - deletion inside
the panel was still one-by-one.

- drop the top-bar button (Can model:update wrapper)
- drop the capacity-coverage alert action that opened the same panel
- remove isDeleteModalOpen state, ModelDeleteDialog import and instance
- delete the orphaned ModelDeleteDialog.tsx (ModelEditDialog stays - it
  is still referenced by resource-manage ModelList)
The type column rendered t(`model.type.${type}`) directly, but the locale
files have no model.type.vlm2/vlm3/vlm4 keys (they are keyed by semantic
name: imageGeneration / videoUnderstanding / audioUnderstanding), so those
rows displayed the raw id string. Add the same id-to-semantic-key mapping
the add dialog uses, covering all ten types.

Also aligns vlm to the dialog label (image understanding) instead of the
legacy model.type.vlm wording.
Copilot AI lite review requested due to automatic review settings September 14, 2026 03:29
Comment thread backend/services/providers/openai_provider.py Dismissed
Comment thread backend/apps/model_managment_app.py Fixed
Comment thread backend/apps/model_managment_app.py Fixed
Comment thread backend/apps/model_managment_app.py Fixed
Comment thread backend/apps/model_managment_app.py Fixed
Comment thread backend/apps/model_managment_app.py Fixed
…points

SSRF (critical) in openai_provider.get_models: the operator-supplied
base_url was fetched as-is. Add _validate_provider_base_url guard before
the request: scheme must be http/https, host required, private / link-local
/ multicast / reserved IP literals rejected (cloud metadata endpoints,
internal routers). Plain DNS names and the documented localhost/127.0.0.1
local-LLM exemption are allowed. Validation errors flow through the
existing _classify_provider_error path as provider fetch failures.

Information exposure (medium x5) in model_managment_app catalog endpoints:
the exception text was interpolated into the JSON response body, which can
leak stack traces / internal details to the caller. Replace with fixed
messages; the exception detail is already logged server-side via
logger.warning. Affected: /catalog/all, /catalog/providers,
/catalog/inference_field_specs, /catalog/providers/{provider}/models,
/catalog/providers/{provider}/models/{model_name}.

Copilot AI 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.

🟡 Changes recommended

Unresolved critical and moderate findings affect runtime behavior, API contracts, tests, security, and deployment.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This pull request expands model configuration across the backend, SDK, frontend, persistence, catalog, and deployment layers.

Changes:

  • Adds model catalogs, provider discovery, and capacity suggestions.
  • Adds inference parameters and agent/knowledge-base overrides.
  • Updates model UI, connectivity checks, migrations, tests, and deployment wiring.

Unresolved findings include catalog mismatches, provider and TLS issues, dropped overrides, exception/configuration problems, an invalid test, an incorrect frontend port, and an unpinned catalog dependency.

File summaries
File Reviewed change
test/backend/test_model_consts.py Tests model inference-parameter schemas and defaults.
test/backend/configs/test_model_catalog_loader.py Tests catalog loading and defaults.
test/backend/configs/__init__.py Initializes the backend test package.
sdk/nexent/core/models/openai_llm.py Adds inference parameters to connectivity checks.
frontend/types/modelConfig.ts Defines model, catalog, and inference types.
frontend/types/agentConfig.ts Defines agent override types.
frontend/stores/agentStore.ts Tracks agent draft model overrides.
frontend/stores/agentConfigStore.ts Tracks editable agent configuration state.
frontend/services/modelService.ts Handles model, catalog, batch, and inference API operations.
frontend/services/api.ts Provides frontend API helpers.
frontend/services/agentConfigService.ts Maps agent configuration API data.
frontend/server.js Configures the production frontend server.
frontend/hooks/model/useModelCatalog.ts Loads model catalog data.
frontend/hooks/model/useInferenceFieldSpecs.ts Loads inference field specifications.
frontend/app/[locale]/newchat/assistant-ui/thread-list.tsx Adds batch conversation selection and deletion.
frontend/app/[locale]/models/components/model/ModelOverrideModal.tsx Provides model override editing.
frontend/app/[locale]/models/components/model/ModelListCard.tsx Renders model list cards.
frontend/app/[locale]/models/components/model/ModelItemCard.tsx Renders individual model cards.
frontend/app/[locale]/models/components/model/ModelEditDialogV2.tsx Edits model configuration and inference defaults.
frontend/app/[locale]/models/components/model/ModelCapacityFields.tsx Renders model capacity settings.
frontend/app/[locale]/models/components/model/ModelAdvancedSettings.tsx Renders advanced inference settings.
frontend/app/[locale]/models/components/model/DefaultModelDialog.tsx Configures default models.
frontend/app/[locale]/knowledges/KnowledgeBaseConfiguration.tsx Adds knowledge-base embedding overrides.
frontend/app/[locale]/knowledges/components/document/DocumentList.tsx Provides knowledge-base document controls.
frontend/app/[locale]/agents/components/agent-prompt.tsx Adds per-model agent overrides.
deploy/sql/migrations/v2.6.0_0806_add_model_inference_params.sql Persists model inference parameters.
deploy/images/dockerfiles/main/Dockerfile Bundles the runtime model catalog.
backend/services/providers/openai_provider.py Discovers models from OpenAI-compatible providers.
backend/services/model_provider_service.py Coordinates provider discovery.
backend/services/model_management_service.py Builds provider model lists.
backend/services/model_health_service.py Handles model health and connectivity checks.
backend/services/model_gateway_service.py Maps inference parameters into gateway requests.
backend/services/model_capacity_suggestion_service.py Provides catalog and LiteLLM capacity suggestions.
backend/management/services/agent/service.py Persists agent override updates.
backend/management/services/agent/management.py Manages agent configuration operations.
backend/database/model_management_db.py Filters and persists model parameters.
backend/database/db_models.py Defines model and agent database fields.
backend/database/agent_db.py Persists agent model overrides.
backend/consts/model.py Defines model catalog and inference schemas.
backend/consts/const.py Defines shared configuration constants.
backend/configs/model_catalog.json Provides preset provider and model metadata.
backend/configs/model_catalog_loader.py Loads and normalizes the model catalog.
backend/configs/__init__.py Initializes the backend configuration package.
backend/apps/model_managment_app.py Exposes catalog and management endpoints.
backend/agents/create_agent_info.py Applies runtime agent model overrides.
Review details

Suppressed comments (13)

backend/services/model_gateway_service.py:95

  • This helper drops every fixed inference field and returns only extra_params.__custom__. enable_thinking is explicitly stored in extra_params and the model/agent UI sends it there, so gateway adapters silently ignore that setting (including connectivity probes) even though the model record persists it. Merge the supported fixed fields into the adapter request as well, with provider-specific translation where required.
    custom = extra_params.get("__custom__")
    return custom if isinstance(custom, dict) and custom else None

backend/services/providers/openai_provider.py:50

  • When the request supplies model_type, the caller skips name inference, but this provider intentionally leaves model_type off every row. Typed discovery therefore returns rows without their requested type; ModelAddDialogV2 falls back to llm, so embedding/rerank/voice requests can be presented and saved as LLMs. Preserve the requested type in the annotation when it is supplied.

    try:
        ip = ipaddress.ip_address(host)

deploy/images/dockerfiles/main/Dockerfile:78

  • Fetching this runtime dependency from @main makes otherwise identical image builds consume different catalog contents over time. Worse, a transient build-network failure silently writes {}, producing an image with no LiteLLM capacity fallback. Pin a release/commit or vendor a known artifact, and make an unavailable catalog visible rather than silently changing behavior.
    https://cdn.jsdelivr.net/gh/BerriAI/litellm@main/model_prices_and_context_window.json \
    || echo '{}' > /opt/nexent/litellm_models.json

deploy/sql/migrations/v2.6.0_0806_add_model_inference_params.sql:42

  • The frontend now exposes and edits per-knowledge-base embedding overrides, but this migration adds storage only to ag_tenant_agent_t; createKnowledgeBase sends no override field and the knowledge record has no corresponding column. Values changed in the new KB UI are therefore discarded when the KB is created. Add a KB persistence/API path or remove the UI until it is supported.
ALTER TABLE nexent.ag_tenant_agent_t
ADD COLUMN IF NOT EXISTS model_params_override JSONB DEFAULT NULL;

frontend/app/[locale]/agents/components/agent-prompt.tsx:149

  • This effect only depends on configuringModelId, so it can initialize while useInferenceFieldSpecs is still empty and never rerun when the specs request resolves. Opening the override modal during that race leaves the form without the model defaults/spec fields; include the loaded model/specs and the relevant override entry in the initialization dependencies.
  }, [configuringModelId]);

frontend/app/[locale]/models/components/model/ModelAddDialogV2.tsx:924

  • On the custom add path, buildInferenceParamsPayload returns voice fields as snake_case (model_factory, model_appid, access_token), but addCustomModel serializes only the camelCase modelFactory/modelAppid/accessToken properties. Unlike the batch path, these fields are never mapped, so STT/TTS models are created with the default OpenAI-compatible factory and lose required credentials. Add the camelCase voice fields before submitting.
          ...inferencePayload,

frontend/app/[locale]/models/components/model/ModelAddDialogV2.tsx:920

  • The custom-submit path never copies the successful customConnectivity result into modelParams, unlike the batch path. Consequently a model that just passed the connectivity probe is created without connect_status and is stored as not_detected despite the new API field intended to persist the verified status.
        const modelParams: any = {
          name: customForm.name,
          type: resolvedModelType,
          url: customForm.url,
          apiKey: customForm.apiKey.trim() === "" ? "sk-no-api-key" : customForm.apiKey,

frontend/app/[locale]/models/components/model/ModelAdvancedSettings.tsx:38

  • This documentation says temperature, top_p, and extra_params are not included, but the same component classifies temperature/top_p as dedicated keys and buildInferenceParamsPayload sends them. The contradiction makes the storage contract misleading and can lead future changes to remove working fields; update the comment to describe dedicated columns plus extra_params JSONB accurately.
//  - temperature / top_p / extra_params and other v2.6.0 additions are NOT
//    included — the new dialog matches the original ModelAddDialog's parameter
//    set without adding new inference parameters.

frontend/services/modelService.ts:387

  • The method now advertises type as optional and says each model carries its own type, but /model/batch_create still validates BatchCreateModelsRequest.type as required and the backend batch service overwrites every model's model_type with the top-level value. Omitting type therefore yields a 422, while per-model types are not honored; update the backend contract/service or keep this field required.
    frontend/services/modelService.ts:1301
  • The manage batch endpoint has the same contract mismatch: this signature allows type to be omitted, but ManageBatchCreateModelsRequest.type is required and batch_create_models_for_tenant indexes the key unconditionally. A caller following this type definition receives a validation error before the request reaches the service; either update the backend for per-row types or keep type required.
    frontend/services/modelService.ts:115
  • This helper is used by the update paths as well as create. Clearing an existing field in ModelEditDialogV2 removes it from buildInferenceParamsPayload, so temperature, top_p, or an emptied extra_params map becomes undefined here and is omitted from the PATCH-like request; the backend then leaves the old database value intact. Update requests need an explicit clear representation (for example null) distinct from an omitted field.
    frontend/services/modelService.ts:1406
  • This manage-list method also advertises an optional type, but /model/manage/provider/list still uses ManageProviderModelListRequest.model_type as a required field. A caller following this signature without type receives a 422; keep it required or update that request model and the service to support all-type discovery.
    frontend/types/modelConfig.ts:240
  • The backend catalog profile emits chunk_batch (see ModelCatalogProfile and model_dump()), but this interface declares chunking_batch_size and getFullCatalog() performs no mapping. The documented 1:1 API type is therefore wrong and typed consumers reading the declared field will get undefined.
  • Files reviewed: 47/50 changed files
  • Comments generated: 11
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread backend/apps/model_managment_app.py Outdated
Comment thread backend/consts/model.py
Comment thread backend/services/model_management_service.py
Comment thread backend/services/model_provider_service.py
Comment thread backend/services/providers/openai_provider.py Outdated
Comment thread frontend/types/modelConfig.ts Outdated
Comment thread test/backend/configs/test_model_catalog_loader.py Outdated
Comment thread test/backend/test_model_consts.py Outdated
Comment thread frontend/app/[locale]/knowledges/KnowledgeBaseConfiguration.tsx
Comment thread backend/services/model_capacity_suggestion_service.py
ljy added 6 commits September 14, 2026 14:24
Real bugs (blocked the unit-test CI job):
- test_model_consts.py: corrupted multi-byte string literal (truncated
  mid-character) made the module unparseable; restore the intended
  default title assertion.
- test_model_catalog_loader.py: read p.provider_key /
  get_model_profile(p.provider_key, ...) but the Pydantic
  ModelCatalogProviderInfo model exposes id; align to the actual field.

Latent issues flagged by review:
- model_managment_app.py: the catalog-import fallback handler logged via
  the module logger before it was initialized, raising NameError on the
  graceful-degradation path; log via logging.getLogger directly.
- useModelCatalog.ts + types: provider summary declared
  provider_key/supported_model_types while /catalog/providers serializes
  id/supported_types (Pydantic dump). Align the frontend type and hook
  maps to the wire names. ModelCatalogModelEntry.provider_key stays as
  is - the /catalog/all model entries do carry provider_key.
The loader normalizes each catalog model entry into a ModelCatalogProfile
instance (not a raw dict), so asserting model_type in model_cfg fails
with TypeError on the Pydantic model. Accept both the raw dict form and
the normalized instance via getattr. Verified in-container: 8 passed.
@jeffwu-1999
jeffwu-1999 merged commit d5d345a into develop Sep 15, 2026
15 of 16 checks passed
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.

6 participants