diff --git a/apps/web/vue3/index_ml.html b/apps/web/vue3/index_ml.html index 0f5967946..adc74f6de 100644 --- a/apps/web/vue3/index_ml.html +++ b/apps/web/vue3/index_ml.html @@ -2158,7 +2158,7 @@ {{ ragProgress.current || '正在知识库中查找相关内容……' }} - 停止等待 + {{ t('stop-waiting') }}
diff --git a/gfa_core/mas/agents/conversation_tools.py b/gfa_core/mas/agents/conversation_tools.py index 6e4bcc4b4..7c253712e 100644 --- a/gfa_core/mas/agents/conversation_tools.py +++ b/gfa_core/mas/agents/conversation_tools.py @@ -264,6 +264,7 @@ class RecognizeAnalysisIntentArgs(BaseModel): query: str job_id: str = "" prefix: str = "" + language: str = "zh" _job_id_is_local = field_validator("job_id")(_validate_job_id) _prefix_is_literal = field_validator("prefix")(_validate_prefix) @@ -1604,21 +1605,29 @@ def build_plantai_conversation_tools( *, workflow_id: str | None = None, guidance: bool = False, + language: str = "zh", ) -> str: """Adapt MainAgent memory to the original IntentAgent text contract.""" text = str(query or "").strip() + en = language == "en" + if ( + text.startswith("执行数据准备(genome_prepare)") + and "当前业务动作已由数据准备契约唯一确定" in text + ): + return text if goal_ledger is None: return text terms = goal_ledger.user_terms context: list[str] = [] family = str(terms.get("gene_family") or "").strip() if family: - context.append(f"基因家族 {family}") - for key, label in ( - ("target_species", "目标物种"), - ("reference_species", "参考物种"), - ("comparative_species", "比较物种"), + context.append(f"Gene family: {family}" if en else f"基因家族 {family}") + for key, label_zh, label_en in ( + ("target_species", "目标物种", "Target species"), + ("reference_species", "参考物种", "Reference species"), + ("comparative_species", "比较物种", "Comparative species"), ): + label = label_en if en else label_zh values = terms.get(key) or () if isinstance(values, (list, tuple)): cleaned = [ @@ -1638,21 +1647,39 @@ def build_plantai_conversation_tools( if mode == "whole_genome": enabled_designs = "、".join(business_context["enabled_designs"]) disabled_designs = "、".join(business_context["disabled_designs"]) - context.append( - f"RNA-seq业务模式 全基因组;{experiment_design} 是实验设计权威输入;" - f"可解释设计为 {enabled_designs},{disabled_designs} 本轮禁用;" - "设计或 batch 降级不得静默发生" - ) + if en: + context.append( + f"RNA-seq mode: whole genome; {experiment_design} is the authoritative experimental design input; " + f"interpretable designs: {enabled_designs}, {disabled_designs} disabled this round; " + "design or batch downgrades must not happen silently" + ) + else: + context.append( + f"RNA-seq业务模式 全基因组;{experiment_design} 是实验设计权威输入;" + f"可解释设计为 {enabled_designs},{disabled_designs} 本轮禁用;" + "设计或 batch 降级不得静默发生" + ) else: - context.append( - "RNA-seq业务模式 基因家族成员;使用已成功的全基因组差异表达结果" - "和精确确认的基因家族成员进行投影;不得自动选择首个成员文件," - "不得隐式重跑差异表达" - ) + if en: + context.append( + "RNA-seq mode: gene family member; use successful whole-genome differential expression results " + "and precisely confirmed gene family members for projection; must not auto-select the first member file, " + "must not implicitly re-run differential expression" + ) + else: + context.append( + "RNA-seq业务模式 基因家族成员;使用已成功的全基因组差异表达结果" + "和精确确认的基因家族成员进行投影;不得自动选择首个成员文件," + "不得隐式重跑差异表达" + ) elif rna_route == "whole_genome": - context.append("RNA-seq模式 全基因组") + context.append( + "RNA-seq mode: whole genome" if en else "RNA-seq模式 全基因组" + ) elif rna_route == "family_member": - context.append("RNA-seq模式 基因家族成员") + context.append( + "RNA-seq mode: gene family member" if en else "RNA-seq模式 基因家族成员" + ) job_id = bound_job_id or str(terms.get("active_job_id") or "").strip() formal_config_exists = bool( job_id and (project_root / "input" / job_id / "config.xlsx").is_file() @@ -1686,15 +1713,62 @@ def build_plantai_conversation_tools( and family_matches ): subfamily_confirm_observed = True - if config_confirmed: - context.append("正式 config.xlsx 已确认") + genome_prepare_observed = False + canonical_request = None + if config_confirmed and not genome_prepare_observed: + if en: + context.append( + "Formal config.xlsx confirmed; this indicates configuration has been verified, " + "not that data preparation is complete. No data preparation completion evidence in current job; " + "specific analysis intent and stages still determined by the existing analysis system" + ) + else: + context.append( + "正式 config.xlsx 已确认;这只表示配置已核对,不等于数据准备已经完成," + "当前 job 尚无数据准备完成证据;具体分析意图和阶段仍由现有分析系统判断" + ) + if guidance and workflow_id in { + "data_preparation", + "gene_family", + "rnaseq_whole_genome", + "rnaseq_family_member", + }: + contract = load_canonical_workflow_contract("data_preparation") + transition = next( + item + for item in contract.transitions + if item.from_state_id == "config_confirmed" + ) + actions = {item.id: item for item in contract.actions} + target_stage = actions[transition.action_id].target_stage + if en: + canonical_request = ( + f"Execute data preparation ({target_stage})\n" + "Business action uniquely determined by data preparation contract" + ) + else: + canonical_request = ( + f"执行数据准备({target_stage})\n" + "当前业务动作已由数据准备契约唯一确定" + ) if family and subfamily_confirm_observed: - context.append( - "当前 job 的 subfamily_confirm 已成功完成,家族成员和亚家族分类表已确认," - "这是当前项目状态事实;具体分析意图和阶段仍由现有分析系统判断" - ) + if en: + context.append( + "Current job's subfamily_confirm completed successfully; " + "family members and subfamily classification table confirmed. " + "This is a current project state fact; specific analysis intent and stages still determined by the existing analysis system" + ) + else: + context.append( + "当前 job 的 subfamily_confirm 已成功完成,家族成员和亚家族分类表已确认," + "这是当前项目状态事实;具体分析意图和阶段仍由现有分析系统判断" + ) + if canonical_request: + return canonical_request if not context: return text + if en: + return f"{text}\nConfirmed context: {'; '.join(context)}." return f"{text}\n已确认上下文:{';'.join(context)}。" registry.set_analysis_handoff_resolver(intent_query_with_confirmed_context) @@ -1711,7 +1785,7 @@ def build_plantai_conversation_tools( receiver="intent_v2", message_type="recognize_intent", payload={ - "query": intent_query_with_confirmed_context(args.query), + "query": intent_query_with_confirmed_context(args.query, language=args.language), "job_id": job_id, "prefix": args.prefix, "workspace": str(project_root / "workspace" / job_id) if job_id else "",