diff --git a/internal/service/model_service.go b/internal/service/model_service.go index 92a8c0d5b3..f0ca72b687 100644 --- a/internal/service/model_service.go +++ b/internal/service/model_service.go @@ -3087,12 +3087,14 @@ func (m *ModelProviderService) ResolveModelID(tenantID string, modelType entity. return "", err } - // Builtin provider is a local service (TEI), not a tenant-enrolled - // provider. There is no row in tenant_model_provider for it, so skip - // database lookups. Mirrors GetModelConfigFromProviderInstance's - // Builtin short-circuit and Python's resolve_model_id which returns - // None for Builtin TEI embeddings. - if modelType == entity.ModelTypeEmbedding && providerName == "Builtin" { + // Builtin provider: Builtin models (e.g. local TEI embeddings) have no + // tenant_model_instance records, so there is no tenant-scoped model ID to + // resolve. Downstream resolution (ResolveModelConfig / getModelConfig) + // falls through to parseModelName → Builtin routing, which already works. + if providerName == "Builtin" && modelType == entity.ModelTypeEmbedding { + if builtinDriver := modelModule.GetBuiltinEmbeddingModel(pureModelName); builtinDriver == nil { + return "", fmt.Errorf("builtin embedding model %q not found", pureModelName) + } return "", nil } diff --git a/internal/service/tenant.go b/internal/service/tenant.go index ffee7b83ef..9aaf04c59b 100644 --- a/internal/service/tenant.go +++ b/internal/service/tenant.go @@ -703,6 +703,24 @@ func (s *TenantService) checkModelAvailable(tenantID, providerName, instanceName return err } + // Static bypass: deepdoc is a built-in model that doesn't need DB checks (mirrors Python _check_model_available). + if providerName == "infiniflow" && instanceName == "default" && modelName == "deepdoc" { + return nil + } + + // Static bypass: OCR with infiniflow@default@deepdoc is always enabled (mirrors Python _check_model_available). + if modelType == "ocr" && providerName == "infiniflow" && instanceName == "default" && modelName == "deepdoc" { + return nil + } + + // Static bypass: TEI Builtin embedding model when COMPOSE_PROFILES includes tei- (mirrors Python _check_model_available). + composeProfiles := common.GetEnv(common.EnvComposeProfiles) + teiModel := common.GetEnv(common.EnvTEIModel) + if modelType == "embedding" && strings.Contains(composeProfiles, "tei-") && teiModel != "" && + modelName == teiModel && (providerName == "" || providerName == "Builtin") { + return nil + } + // Check if the provider and instance exists modelProvider, err := s.modelProviderDAO.GetByTenantIDAndProviderName(tenantID, providerName) if err != nil { @@ -798,19 +816,25 @@ func (s *TenantService) SetTenantDefaultModels(userID, modelProvider, modelInsta return err } if modelID == "" { - modelProviderEntity, err := s.modelProviderDAO.GetByTenantIDAndProviderName(ownedTenant.TenantID, modelProvider) - if err != nil { - return err + // Builtin provider doesn't use tenant_model rows; leave tenantModelID nil + // (mirrors Python resolve_model_id returning None for Builtin). + if modelProvider == "Builtin" { + tenantModelID = nil + } else { + modelProviderEntity, err := s.modelProviderDAO.GetByTenantIDAndProviderName(ownedTenant.TenantID, modelProvider) + if err != nil { + return err + } + modelInstanceEntity, err := s.modelInstanceDAO.GetByProviderIDAndInstanceName(modelProviderEntity.ID, modelInstance) + if err != nil { + return err + } + modelEntity, err := s.modelDAO.GetModelByProviderIDAndInstanceIDAndModelName(modelProviderEntity.ID, modelInstanceEntity.ID, modelName) + if err != nil { + return err + } + tenantModelID = modelEntity.ID } - modelInstanceEntity, err := s.modelInstanceDAO.GetByProviderIDAndInstanceName(modelProviderEntity.ID, modelInstance) - if err != nil { - return err - } - modelEntity, err := s.modelDAO.GetModelByProviderIDAndInstanceIDAndModelName(modelProviderEntity.ID, modelInstanceEntity.ID, modelName) - if err != nil { - return err - } - tenantModelID = modelEntity.ID } defaultModel = fmt.Sprintf("%s@%s@%s", modelName, modelInstance, modelProvider) } else { diff --git a/rag/advanced_rag/knowlege_compile/wiki.py b/rag/advanced_rag/knowlege_compile/wiki.py index 3e4da5a273..86ede89057 100644 --- a/rag/advanced_rag/knowlege_compile/wiki.py +++ b/rag/advanced_rag/knowlege_compile/wiki.py @@ -1991,9 +1991,7 @@ async def _wiki_planning_call( entities_summary = "\n".join(_wiki_format_entity_for_plan(e, reconciliation) for e in sorted_entities[:200]) or " (none)" concepts_summary = "\n".join(_wiki_format_concept_for_plan(c, reconciliation) for c in sorted_concepts[:200]) or " (none)" - topics_summary = "\n".join( - f" - {t.strip()}" for t in raw_topics[:200] if isinstance(t, str) and t.strip() - ) or " (none)" + topics_summary = "\n".join(f" - {t.strip()}" for t in raw_topics[:200] if isinstance(t, str) and t.strip()) or " (none)" kb_lines: list[str] = [] for name, rec in reconciliation.items(): @@ -3397,11 +3395,7 @@ async def wiki_refine_from_plan( all_claims = plan.get("_claims") or [] # ``all_plan_slugs`` is implicitly deduped now (pages_spec is unique). all_plan_slugs = [p["slug"] for p in pages_spec] - page_titles = { - str(p["slug"]): str(p.get("title") or "").strip() - for p in pages_spec - if p.get("slug") and str(p.get("title") or "").strip() - } + page_titles = {str(p["slug"]): str(p.get("title") or "").strip() for p in pages_spec if p.get("slug") and str(p.get("title") or "").strip()} # Build canonical entity/concept lookups for evidence fallback. When MAP # produced no claims (a real failure mode we've seen on Chinese / dense