From 91bffdf88d2281643cf66d1239e708d4f990d6a1 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:21:27 +0000 Subject: [PATCH 001/373] fix(frontend): derive api base url from runtime origin --- frontend/src/api/index.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index e2d9465b..ca932dc9 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -1,8 +1,21 @@ import axios from 'axios' +const resolveBaseURL = () => { + const envBaseURL = import.meta.env.VITE_API_BASE_URL + if (envBaseURL && envBaseURL.trim()) { + return envBaseURL + } + + if (typeof window !== 'undefined' && window.location) { + return window.location.origin + } + + return '' +} + // 创建axios实例 const service = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5001', + baseURL: resolveBaseURL(), timeout: 300000, // 5分钟超时(本体生成可能需要较长时间) headers: { 'Content-Type': 'application/json' From 5ee94401014b65b1ff726062a78abb3b8f323672 Mon Sep 17 00:00:00 2001 From: ailuntz Date: Tue, 10 Mar 2026 15:27:44 +0800 Subject: [PATCH 002/373] Use SPDX license string --- backend/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 4f5361d5..a4394a0b 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -3,7 +3,7 @@ name = "mirofish-backend" version = "0.1.0" description = "MiroFish - 简洁通用的群体智能引擎,预测万物" requires-python = ">=3.11" -license = { text = "AGPL-3.0" } +license = "AGPL-3.0" authors = [ { name = "MiroFish Team" } ] From d5e50e5e037e087aa177196fe37a95a640ff3b25 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:30:13 +0000 Subject: [PATCH 003/373] feat: harden upstream triage and llm compatibility --- .env.example | 3 +- AGENTS.md | 150 +++++++++++++++++++++++++++++++ GOALS.md | 40 +++++++++ README-EN.md | 5 +- README.md | 3 + backend/app/config.py | 18 ++-- backend/app/utils/llm_client.py | 44 ++++++--- backend/tests/conftest.py | 7 ++ backend/tests/test_llm_client.py | 67 ++++++++++++++ docs/upstream-open-summary.md | 32 +++++++ docs/upstream-triage.md | 22 +++++ scripts/sync_upstream_github.py | 120 +++++++++++++++++++++++++ 12 files changed, 493 insertions(+), 18 deletions(-) create mode 100644 AGENTS.md create mode 100644 GOALS.md create mode 100644 backend/tests/conftest.py create mode 100644 backend/tests/test_llm_client.py create mode 100644 docs/upstream-open-summary.md create mode 100644 docs/upstream-triage.md create mode 100644 scripts/sync_upstream_github.py diff --git a/.env.example b/.env.example index 78a3b72c..3280a6de 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ # LLM API配置(支持 OpenAI SDK 格式的任意 LLM API) +# 也兼容标准 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL 环境变量 # 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/ # 注意消耗较大,可先进行小于40轮的模拟尝试 LLM_API_KEY=your_api_key_here @@ -13,4 +14,4 @@ ZEP_API_KEY=your_zep_api_key_here # 注意如果不使用加速配置,env文件中就不要出现下面的配置项 LLM_BOOST_API_KEY=your_api_key_here LLM_BOOST_BASE_URL=your_base_url_here -LLM_BOOST_MODEL_NAME=your_model_name_here \ No newline at end of file +LLM_BOOST_MODEL_NAME=your_model_name_here diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..c951c075 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,150 @@ +# Agent Instructions + +This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started. + +## Quick Reference + +```bash +bd ready # Find available work +bd show # View issue details +bd update --claim # Claim work atomically +bd close # Complete work +bd sync # Sync with git +``` + +## Non-Interactive Shell Commands + +**ALWAYS use non-interactive flags** with file operations to avoid hanging on confirmation prompts. + +Shell commands like `cp`, `mv`, and `rm` may be aliased to include `-i` (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input. + +**Use these forms instead:** +```bash +# Force overwrite without prompting +cp -f source dest # NOT: cp source dest +mv -f source dest # NOT: mv source dest +rm -f file # NOT: rm file + +# For recursive operations +rm -rf directory # NOT: rm -r directory +cp -rf source dest # NOT: cp -r source dest +``` + +**Other commands that may prompt:** +- `scp` - use `-o BatchMode=yes` for non-interactive +- `ssh` - use `-o BatchMode=yes` to fail instead of prompting +- `apt-get` - use `-y` flag +- `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var + + +## Issue Tracking with bd (beads) + +**IMPORTANT**: This project uses **bd (beads)** for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods. + +### Why bd? + +- Dependency-aware: Track blockers and relationships between issues +- Version-controlled: Built on Dolt with cell-level merge +- Agent-optimized: JSON output, ready work detection, discovered-from links +- Prevents duplicate tracking systems and confusion + +### Quick Start + +**Check for ready work:** + +```bash +bd ready --json +``` + +**Create new issues:** + +```bash +bd create "Issue title" --description="Detailed context" -t bug|feature|task -p 0-4 --json +bd create "Issue title" --description="What this issue is about" -p 1 --deps discovered-from:bd-123 --json +``` + +**Claim and update:** + +```bash +bd update --claim --json +bd update bd-42 --priority 1 --json +``` + +**Complete work:** + +```bash +bd close bd-42 --reason "Completed" --json +``` + +### Issue Types + +- `bug` - Something broken +- `feature` - New functionality +- `task` - Work item (tests, docs, refactoring) +- `epic` - Large feature with subtasks +- `chore` - Maintenance (dependencies, tooling) + +### Priorities + +- `0` - Critical (security, data loss, broken builds) +- `1` - High (major features, important bugs) +- `2` - Medium (default, nice-to-have) +- `3` - Low (polish, optimization) +- `4` - Backlog (future ideas) + +### Workflow for AI Agents + +1. **Check ready work**: `bd ready` shows unblocked issues +2. **Claim your task atomically**: `bd update --claim` +3. **Work on it**: Implement, test, document +4. **Discover new work?** Create linked issue: + - `bd create "Found bug" --description="Details about what was found" -p 1 --deps discovered-from:` +5. **Complete**: `bd close --reason "Done"` + +### Auto-Sync + +bd automatically syncs with git: + +- Exports to `.beads/issues.jsonl` after changes (5s debounce) +- Imports from JSONL when newer (e.g., after `git pull`) +- No manual export/import needed! + +### Important Rules + +- ✅ Use bd for ALL task tracking +- ✅ Always use `--json` flag for programmatic use +- ✅ Link discovered work with `discovered-from` dependencies +- ✅ Check `bd ready` before asking "what should I work on?" +- ❌ Do NOT create markdown TODO lists +- ❌ Do NOT use external issue trackers +- ❌ Do NOT duplicate tracking systems + +For more details, see README.md and docs/QUICKSTART.md. + +## Landing the Plane (Session Completion) + +**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds. + +**MANDATORY WORKFLOW:** + +1. **File issues for remaining work** - Create issues for anything that needs follow-up +2. **Run quality gates** (if code changed) - Tests, linters, builds +3. **Update issue status** - Close finished work, update in-progress items +4. **PUSH TO REMOTE** - This is MANDATORY: + ```bash + git pull --rebase + bd sync + git push + git status # MUST show "up to date with origin" + ``` +5. **Clean up** - Clear stashes, prune remote branches +6. **Verify** - All changes committed AND pushed +7. **Hand off** - Provide context for next session + +**CRITICAL RULES:** +- Work is NOT complete until `git push` succeeds +- NEVER stop before pushing - that leaves work stranded locally +- NEVER say "ready to push when you are" - YOU must push +- If push fails, resolve and retry until it succeeds + + diff --git a/GOALS.md b/GOALS.md new file mode 100644 index 00000000..732fd8e6 --- /dev/null +++ b/GOALS.md @@ -0,0 +1,40 @@ +# Goals + +Keep MiroFish shippable while continuously triaging upstream changes and improving OpenAI-compatible backend interoperability. + +## North Stars + +- Safe upstream fixes land quickly without destabilizing the fork. +- OpenAI-compatible and local LLM backends work without code edits outside configuration. + +## Anti Stars + +- Broad merges that mix unrelated upstream changes into one risky batch. +- Backend compatibility claims that are undocumented or unsupported by tests. + +## Directives + +### 1. Maintain Upstream Triage + +Continuously ingest the upstream issue and pull-request backlog into beads-backed work so the fork has a current, execution-ready queue. + +**Steer:** increase + +### 2. Prefer Safe, Incremental Upstream Adoption + +Cherry-pick or supersede the smallest safe upstream fixes first, especially around configuration, parsing, and compatibility behavior. + +**Steer:** increase + +### 3. Keep Backend Compatibility Explicit + +Support both project-specific `LLM_*` settings and standard OpenAI-compatible environment variables, then document the supported setup paths. + +**Steer:** increase + +## Gates + +| ID | Check | Weight | Description | +|----|-------|--------|-------------| +| frontend-build | `npm run build` | 4 | Frontend production build succeeds | +| backend-pytest | `cd backend && uv run pytest -q` | 5 | Backend regression tests pass | diff --git a/README-EN.md b/README-EN.md index cd24e83e..f4a1b57c 100644 --- a/README-EN.md +++ b/README-EN.md @@ -116,6 +116,7 @@ cp .env.example .env ```env # LLM API Configuration (supports any LLM API with OpenAI SDK format) +# Standard OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL aliases also work # Recommended: Alibaba Qwen-plus model via Bailian Platform: https://bailian.console.aliyun.com/ # High consumption, try simulations with fewer than 40 rounds first LLM_API_KEY=your_api_key @@ -127,6 +128,8 @@ LLM_MODEL_NAME=qwen-plus ZEP_API_KEY=your_zep_api_key ``` +The backend now accepts both the project-specific `LLM_*` variables and the standard `OPENAI_*` aliases, so you can point MiroFish directly at OpenAI, Codex-compatible gateways, LM Studio, Ollama, or other OpenAI-compatible backends without extra code changes. + #### 2. Install Dependencies ```bash @@ -200,4 +203,4 @@ MiroFish's simulation engine is powered by **[OASIS (Open Agent Social Interacti Star History Chart - \ No newline at end of file + diff --git a/README.md b/README.md index a47976c4..347d7fa3 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ cp .env.example .env ```env # LLM API配置(支持 OpenAI SDK 格式的任意 LLM API) +# 也支持直接使用 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL # 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/ # 注意消耗较大,可先进行小于40轮的模拟尝试 LLM_API_KEY=your_api_key @@ -127,6 +128,8 @@ LLM_MODEL_NAME=qwen-plus ZEP_API_KEY=your_zep_api_key ``` +说明:后端现在同时识别项目内的 `LLM_*` 配置和标准 `OPENAI_*` 配置,因此可直接接入 OpenAI、Codex 兼容网关、LM Studio、Ollama 等 OpenAI-compatible 服务。 + #### 2. 安装依赖 ```bash diff --git a/backend/app/config.py b/backend/app/config.py index 953dfa50..5da36bb3 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -17,6 +17,15 @@ load_dotenv(override=True) +def _env(*names, default=None): + """Return the first configured environment variable from the provided aliases.""" + for name in names: + value = os.environ.get(name) + if value not in (None, ''): + return value + return default + + class Config: """Flask配置类""" @@ -28,9 +37,9 @@ class Config: JSON_AS_ASCII = False # LLM配置(统一使用OpenAI格式) - LLM_API_KEY = os.environ.get('LLM_API_KEY') - LLM_BASE_URL = os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1') - LLM_MODEL_NAME = os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini') + LLM_API_KEY = _env('LLM_API_KEY', 'OPENAI_API_KEY') + LLM_BASE_URL = _env('LLM_BASE_URL', 'OPENAI_BASE_URL', default='https://api.openai.com/v1') + LLM_MODEL_NAME = _env('LLM_MODEL_NAME', 'OPENAI_MODEL', default='gpt-4o-mini') # Zep配置 ZEP_API_KEY = os.environ.get('ZEP_API_KEY') @@ -68,8 +77,7 @@ def validate(cls): """验证必要配置""" errors = [] if not cls.LLM_API_KEY: - errors.append("LLM_API_KEY 未配置") + errors.append("LLM_API_KEY / OPENAI_API_KEY 未配置") if not cls.ZEP_API_KEY: errors.append("ZEP_API_KEY 未配置") return errors - diff --git a/backend/app/utils/llm_client.py b/backend/app/utils/llm_client.py index 6c1a81f4..dd539175 100644 --- a/backend/app/utils/llm_client.py +++ b/backend/app/utils/llm_client.py @@ -25,7 +25,7 @@ def __init__( self.model = model or Config.LLM_MODEL_NAME if not self.api_key: - raise ValueError("LLM_API_KEY 未配置") + raise ValueError("LLM_API_KEY / OPENAI_API_KEY 未配置") self.client = OpenAI( api_key=self.api_key, @@ -62,10 +62,37 @@ def chat( kwargs["response_format"] = response_format response = self.client.chat.completions.create(**kwargs) - content = response.choices[0].message.content - # 部分模型(如MiniMax M2.5)会在content中包含思考内容,需要移除 - content = re.sub(r'[\s\S]*?', '', content).strip() + content = response.choices[0].message.content or "" + # 部分模型会在 content 中夹带 ...,且标签大小写不固定 + content = re.sub(r']*>[\s\S]*?', '', content, flags=re.IGNORECASE).strip() return content + + @staticmethod + def _extract_json_payload(response_text: str) -> str: + """从混合文本中提取可解析的 JSON 负载。""" + text = (response_text or "").strip().lstrip('\ufeff') + + text = re.sub(r'^```(?:json)?\s*\n?', '', text, flags=re.IGNORECASE) + text = re.sub(r'\n?```\s*$', '', text) + text = text.strip() + + try: + json.loads(text) + return text + except json.JSONDecodeError: + pass + + start = text.find('{') + end = text.rfind('}') + if start != -1 and end != -1 and end > start: + candidate = text[start:end + 1].strip() + try: + json.loads(candidate) + return candidate + except json.JSONDecodeError: + pass + + return text def chat_json( self, @@ -88,16 +115,11 @@ def chat_json( messages=messages, temperature=temperature, max_tokens=max_tokens, - response_format={"type": "json_object"} + # 不设置 response_format,以兼容 LM Studio / Ollama 等仅支持纯文本 JSON 输出的后端 ) - # 清理markdown代码块标记 - cleaned_response = response.strip() - cleaned_response = re.sub(r'^```(?:json)?\s*\n?', '', cleaned_response, flags=re.IGNORECASE) - cleaned_response = re.sub(r'\n?```\s*$', '', cleaned_response) - cleaned_response = cleaned_response.strip() + cleaned_response = self._extract_json_payload(response) try: return json.loads(cleaned_response) except json.JSONDecodeError: raise ValueError(f"LLM返回的JSON格式无效: {cleaned_response}") - diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py new file mode 100644 index 00000000..86a1a5ac --- /dev/null +++ b/backend/tests/conftest.py @@ -0,0 +1,7 @@ +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) diff --git a/backend/tests/test_llm_client.py b/backend/tests/test_llm_client.py new file mode 100644 index 00000000..05cf2b76 --- /dev/null +++ b/backend/tests/test_llm_client.py @@ -0,0 +1,67 @@ +from types import SimpleNamespace + +from app.utils.llm_client import LLMClient + + +def test_extract_json_payload_from_markdown_fence(): + raw = """```json +{"a": 1, "b": [2, 3]} +```""" + + assert LLMClient._extract_json_payload(raw) == '{"a": 1, "b": [2, 3]}' + + +def test_extract_json_payload_with_prefixed_reasoning_text(): + raw = """分析如下: +先思考 +最终答案: +{"entity_types": [], "edge_types": []} +""" + + assert LLMClient._extract_json_payload(raw) == '{"entity_types": [], "edge_types": []}' + + +def test_chat_returns_empty_string_when_content_is_none(monkeypatch): + create_calls = [] + + class FakeCompletions: + def create(self, **kwargs): + create_calls.append(kwargs) + return SimpleNamespace( + choices=[SimpleNamespace(message=SimpleNamespace(content=None))] + ) + + class FakeOpenAI: + def __init__(self, api_key, base_url): + self.chat = SimpleNamespace(completions=FakeCompletions()) + + monkeypatch.setattr("app.utils.llm_client.OpenAI", FakeOpenAI) + + client = LLMClient(api_key="test-key", base_url="https://example.test/v1", model="test-model") + response = client.chat([{"role": "user", "content": "hello"}], response_format={"type": "json_object"}) + + assert response == "" + assert create_calls[0]["response_format"] == {"type": "json_object"} + + +def test_chat_json_omits_response_format_for_compatibility(monkeypatch): + create_calls = [] + + class FakeCompletions: + def create(self, **kwargs): + create_calls.append(kwargs) + return SimpleNamespace( + choices=[SimpleNamespace(message=SimpleNamespace(content='{"ok": true}'))] + ) + + class FakeOpenAI: + def __init__(self, api_key, base_url): + self.chat = SimpleNamespace(completions=FakeCompletions()) + + monkeypatch.setattr("app.utils.llm_client.OpenAI", FakeOpenAI) + + client = LLMClient(api_key="test-key", base_url="https://example.test/v1", model="test-model") + response = client.chat_json([{"role": "user", "content": "hello"}]) + + assert response == {"ok": True} + assert "response_format" not in create_calls[0] diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md new file mode 100644 index 00000000..e822b8f7 --- /dev/null +++ b/docs/upstream-open-summary.md @@ -0,0 +1,32 @@ +# Upstream Triage Snapshot + +- Repository: `666ghj/MiroFish` +- Captured: `2026-03-11T06:28:09.817366+00:00` +- Open issues: `32` +- Open pull requests: `35` + +## Recently Updated Issues + +- #117 ### Feature Request: English Language Support (enhancement) +- #110 阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用 (LLM API) +- #107 镜像问题 (no labels) +- #106 能否采用除了zep的别的知识图谱 (no labels) +- #99 Docker镜像没有arm版本 (enhancement) +- #93 `frontend/src/api/index.js`中的`baseURL`不应该硬编码 (enhancement) +- #92 Upgrade GitHub Actions (enhancement) +- #84 报告生成失败,请问有没有办法重新生成? (question) +- #76 知识图谱构建提供接入 ragflow api 的功能 (Memory Layer) +- #75 Zep 的免费限速会让进度卡99% (no labels) + +## Open Pull Requests + +- #132 docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) +- #131 feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) +- #130 docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) +- #129 fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) +- #127 Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) +- #126 feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) +- #125 fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) +- #124 fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) +- #122 fix(llm_client): remove response_format json_object for local LLM compatibility (`fix/lm-studio-json-object-compat` -> `main`) +- #120 fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md new file mode 100644 index 00000000..afcdeefe --- /dev/null +++ b/docs/upstream-triage.md @@ -0,0 +1,22 @@ +# Upstream Triage + +Last refreshed: `2026-03-11` + +## Current focus + +- Keep a reusable local snapshot of `666ghj/MiroFish` open issues and pull requests. +- Land small, low-risk upstream fixes before considering larger feature branches. +- Make backend compatibility with OpenAI-compatible providers explicit in code and docs. + +## Safe PR candidates reviewed + +- `#115` Use SPDX license string: safe metadata-only cherry-pick. +- `#122` Remove `response_format={"type":"json_object"}` from `chat_json()`: improves compatibility with LM Studio and Ollama-style backends. +- `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. +- `#127` Handle `None` response content: safe guard against provider edge cases. + +## Practical mirror strategy for the fork + +- Mirror the highest-signal upstream PR branches to the fork when they are under active review. +- Keep detailed execution tracking in local beads issues to avoid spamming the fork with every upstream item. +- Use `scripts/sync_upstream_github.py` to refresh a machine-readable snapshot and a concise markdown summary before each new evolve pass. diff --git a/scripts/sync_upstream_github.py b/scripts/sync_upstream_github.py new file mode 100644 index 00000000..df5524d3 --- /dev/null +++ b/scripts/sync_upstream_github.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""Fetch upstream GitHub issues and pull requests into a local summary.""" + +from __future__ import annotations + +import argparse +import json +import os +import sys +import urllib.parse +import urllib.request +from datetime import datetime, timezone +from pathlib import Path + + +def fetch_json(url: str) -> object: + request = urllib.request.Request(url, headers={"User-Agent": "mirofish-upstream-sync"}) + with urllib.request.urlopen(request) as response: + return json.load(response) + + +def github_api(path: str, params: dict[str, object]) -> object: + query = urllib.parse.urlencode(params) + return fetch_json(f"https://api.github.com{path}?{query}") + + +def compact_issue(issue: dict[str, object]) -> dict[str, object]: + return { + "number": issue["number"], + "title": issue["title"], + "url": issue["html_url"], + "created_at": issue["created_at"], + "updated_at": issue["updated_at"], + "labels": [label["name"] for label in issue.get("labels", [])], + "author": issue.get("user", {}).get("login"), + } + + +def compact_pr(pr: dict[str, object]) -> dict[str, object]: + return { + "number": pr["number"], + "title": pr["title"], + "url": pr["html_url"], + "created_at": pr["created_at"], + "updated_at": pr["updated_at"], + "head": pr.get("head", {}).get("ref"), + "base": pr.get("base", {}).get("ref"), + "draft": pr.get("draft", False), + "author": pr.get("user", {}).get("login"), + } + + +def write_summary(path: Path, repo: str, issues: list[dict[str, object]], prs: list[dict[str, object]]) -> None: + lines = [ + "# Upstream Triage Snapshot", + "", + f"- Repository: `{repo}`", + f"- Captured: `{datetime.now(timezone.utc).isoformat()}`", + f"- Open issues: `{len(issues)}`", + f"- Open pull requests: `{len(prs)}`", + "", + "## Recently Updated Issues", + "", + ] + + for issue in issues[:10]: + labels = ", ".join(issue["labels"]) if issue["labels"] else "no labels" + lines.append(f"- #{issue['number']} {issue['title']} ({labels})") + + lines.extend(["", "## Open Pull Requests", ""]) + for pr in prs[:10]: + lines.append(f"- #{pr['number']} {pr['title']} (`{pr['head']}` -> `{pr['base']}`)") + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("\n".join(lines) + "\n", encoding="utf-8") + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--repo", default="666ghj/MiroFish", help="owner/repo to inspect") + parser.add_argument("--state", default="open", help="GitHub state filter") + parser.add_argument("--limit", type=int, default=100, help="Maximum items to fetch per collection") + parser.add_argument("--output", required=True, help="Path to write machine-readable JSON") + parser.add_argument("--summary", required=True, help="Path to write markdown summary") + args = parser.parse_args() + + owner, name = args.repo.split("/", 1) + issue_items = github_api( + f"/repos/{owner}/{name}/issues", + {"state": args.state, "per_page": min(args.limit, 100)}, + ) + pr_items = github_api( + f"/repos/{owner}/{name}/pulls", + {"state": args.state, "per_page": min(args.limit, 100)}, + ) + + issues = [compact_issue(item) for item in issue_items if "pull_request" not in item] + prs = [compact_pr(item) for item in pr_items] + payload = { + "repo": args.repo, + "state": args.state, + "captured_at": datetime.now(timezone.utc).isoformat(), + "issues": issues, + "pull_requests": prs, + } + + output_path = Path(args.output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + write_summary(Path(args.summary), args.repo, issues, prs) + + print( + f"Captured {len(issues)} issues and {len(prs)} pull requests from {args.repo} " + f"into {os.path.relpath(output_path)}" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 7691da81c0c4e3675f39134af20f56a5c81d4f96 Mon Sep 17 00:00:00 2001 From: Sergio Date: Tue, 10 Mar 2026 14:50:04 -0700 Subject: [PATCH 004/373] fix: improve project init error guidance for network failures Fixes 666ghj/MiroFish#121 --- frontend/src/views/Process.vue | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/Process.vue b/frontend/src/views/Process.vue index 2d2d3cc1..8b78da41 100644 --- a/frontend/src/views/Process.vue +++ b/frontend/src/views/Process.vue @@ -564,6 +564,24 @@ const initProject = async () => { } } +const formatProjectInitError = (err) => { + if (!err) return '未知错误' + + if (err.code === 'ECONNABORTED' || String(err.message || '').includes('timeout')) { + return '请求超时(5分钟),请尝试减小文档体积或检查后端模型响应速度' + } + + if (err.message === 'Network Error') { + const apiBase = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5001' + return `无法连接后端服务(${apiBase})。请检查后端是否已启动、跨域/反向代理配置及服务器网络连通性` + } + + const backendMessage = err.response?.data?.error || err.response?.data?.message + if (backendMessage) return backendMessage + + return err.message || '未知错误' +} + // 处理新建项目 - 调用 ontology/generate API const handleNewProject = async () => { const pending = getPendingUpload() @@ -612,7 +630,7 @@ const handleNewProject = async () => { } } catch (err) { console.error('Handle new project error:', err) - error.value = '项目初始化失败: ' + (err.message || '未知错误') + error.value = '项目初始化失败: ' + formatProjectInitError(err) } finally { loading.value = false } From 0a822538bee0c671072c8c965f74945daaeafb7f Mon Sep 17 00:00:00 2001 From: ailuntz Date: Tue, 10 Mar 2026 15:30:16 +0800 Subject: [PATCH 005/373] Upgrade GitHub Actions --- .github/workflows/docker-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index becbdec5..af8fc23a 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -40,7 +40,7 @@ jobs: type=raw,value=latest - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile From 9906b5b172af7b3932028e2888ee24a380d45f84 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:34:24 +0000 Subject: [PATCH 006/373] docs: refresh upstream triage snapshot --- docs/upstream-open-state.json | 700 ++++++++++++++++++++++++++++++++++ docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 16 +- 3 files changed, 716 insertions(+), 2 deletions(-) create mode 100644 docs/upstream-open-state.json diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json new file mode 100644 index 00000000..d050523a --- /dev/null +++ b/docs/upstream-open-state.json @@ -0,0 +1,700 @@ +{ + "repo": "666ghj/MiroFish", + "state": "open", + "captured_at": "2026-03-11T06:33:02.082890+00:00", + "issues": [ + { + "number": 117, + "title": "### Feature Request: English Language Support", + "url": "https://github.com/666ghj/MiroFish/issues/117", + "created_at": "2026-03-10T08:44:18Z", + "updated_at": "2026-03-10T08:46:24Z", + "labels": [ + "enhancement" + ], + "author": "malpaniga" + }, + { + "number": 110, + "title": "阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用", + "url": "https://github.com/666ghj/MiroFish/issues/110", + "created_at": "2026-03-10T01:08:29Z", + "updated_at": "2026-03-10T06:40:37Z", + "labels": [ + "LLM API" + ], + "author": "weilb" + }, + { + "number": 107, + "title": "镜像问题", + "url": "https://github.com/666ghj/MiroFish/issues/107", + "created_at": "2026-03-09T14:44:45Z", + "updated_at": "2026-03-09T14:44:45Z", + "labels": [], + "author": "zhuhw19" + }, + { + "number": 106, + "title": "能否采用除了zep的别的知识图谱", + "url": "https://github.com/666ghj/MiroFish/issues/106", + "created_at": "2026-03-09T13:55:59Z", + "updated_at": "2026-03-10T02:33:21Z", + "labels": [], + "author": "paipaiio" + }, + { + "number": 99, + "title": "Docker镜像没有arm版本", + "url": "https://github.com/666ghj/MiroFish/issues/99", + "created_at": "2026-03-09T06:52:35Z", + "updated_at": "2026-03-09T06:54:58Z", + "labels": [ + "enhancement" + ], + "author": "linqiu919" + }, + { + "number": 93, + "title": "`frontend/src/api/index.js`中的`baseURL`不应该硬编码", + "url": "https://github.com/666ghj/MiroFish/issues/93", + "created_at": "2026-03-08T16:44:24Z", + "updated_at": "2026-03-09T01:53:47Z", + "labels": [ + "enhancement" + ], + "author": "HexStan" + }, + { + "number": 92, + "title": "Upgrade GitHub Actions", + "url": "https://github.com/666ghj/MiroFish/issues/92", + "created_at": "2026-03-08T15:26:04Z", + "updated_at": "2026-03-08T15:28:09Z", + "labels": [ + "enhancement" + ], + "author": "leon-x-labs" + }, + { + "number": 84, + "title": "报告生成失败,请问有没有办法重新生成?", + "url": "https://github.com/666ghj/MiroFish/issues/84", + "created_at": "2026-03-08T08:10:41Z", + "updated_at": "2026-03-09T17:26:28Z", + "labels": [ + "question" + ], + "author": "luchenwei9266" + }, + { + "number": 76, + "title": "知识图谱构建提供接入 ragflow api 的功能", + "url": "https://github.com/666ghj/MiroFish/issues/76", + "created_at": "2026-02-27T12:02:39Z", + "updated_at": "2026-02-28T08:02:11Z", + "labels": [ + "Memory Layer" + ], + "author": "Hitomogami" + }, + { + "number": 75, + "title": "Zep 的免费限速会让进度卡99%", + "url": "https://github.com/666ghj/MiroFish/issues/75", + "created_at": "2026-02-26T08:35:41Z", + "updated_at": "2026-02-28T08:13:33Z", + "labels": [], + "author": "fengkuangyibo" + }, + { + "number": 69, + "title": "模型对接", + "url": "https://github.com/666ghj/MiroFish/issues/69", + "created_at": "2026-02-10T07:53:43Z", + "updated_at": "2026-02-10T07:56:20Z", + "labels": [ + "question" + ], + "author": "wjh-w" + }, + { + "number": 68, + "title": "尝试进行首次模拟,等待了1夜还是在3/5的阶段", + "url": "https://github.com/666ghj/MiroFish/issues/68", + "created_at": "2026-02-10T01:19:08Z", + "updated_at": "2026-03-01T08:29:56Z", + "labels": [ + "question" + ], + "author": "GarretRen" + }, + { + "number": 64, + "title": "一直卡在上传文件错误:Request failed with status code 500", + "url": "https://github.com/666ghj/MiroFish/issues/64", + "created_at": "2026-01-31T13:10:06Z", + "updated_at": "2026-03-10T05:40:36Z", + "labels": [], + "author": "G-LJDS2022" + }, + { + "number": 62, + "title": "很好的创意,专门注册来提提问题和建议啦", + "url": "https://github.com/666ghj/MiroFish/issues/62", + "created_at": "2026-01-28T01:39:38Z", + "updated_at": "2026-01-28T08:34:36Z", + "labels": [], + "author": "piaopiaomiaomiao" + }, + { + "number": 61, + "title": "能否将修改api的功能在前端也实现", + "url": "https://github.com/666ghj/MiroFish/issues/61", + "created_at": "2026-01-27T13:37:15Z", + "updated_at": "2026-01-28T08:35:08Z", + "labels": [], + "author": "skoa323" + }, + { + "number": 60, + "title": "Zep 免费计划 429 限流导致图谱构建失败(请求过密)", + "url": "https://github.com/666ghj/MiroFish/issues/60", + "created_at": "2026-01-24T16:03:41Z", + "updated_at": "2026-01-28T08:36:57Z", + "labels": [], + "author": "Jonah-Wu23" + }, + { + "number": 58, + "title": "使用ollama加载的本地大模型启动引擎时经常会遇到超时问题", + "url": "https://github.com/666ghj/MiroFish/issues/58", + "created_at": "2026-01-24T10:47:13Z", + "updated_at": "2026-01-24T16:18:14Z", + "labels": [], + "author": "ThomasWang071001" + }, + { + "number": 56, + "title": "Zep 本地化实现方案交流专贴", + "url": "https://github.com/666ghj/MiroFish/issues/56", + "created_at": "2026-01-23T07:24:57Z", + "updated_at": "2026-03-06T01:40:22Z", + "labels": [], + "author": "666ghj" + }, + { + "number": 55, + "title": "做了一个基于本地neo4j的版本", + "url": "https://github.com/666ghj/MiroFish/issues/55", + "created_at": "2026-01-23T03:08:03Z", + "updated_at": "2026-01-23T06:27:04Z", + "labels": [], + "author": "xumengke2025-sys" + }, + { + "number": 54, + "title": "太喜欢你这个项目了!给了我巨大的帮助!", + "url": "https://github.com/666ghj/MiroFish/issues/54", + "created_at": "2026-01-23T02:39:53Z", + "updated_at": "2026-01-23T02:39:53Z", + "labels": [], + "author": "zb2947244682" + }, + { + "number": 52, + "title": "API最大长度超过导致程序奔溃", + "url": "https://github.com/666ghj/MiroFish/issues/52", + "created_at": "2026-01-22T13:25:33Z", + "updated_at": "2026-01-22T13:25:33Z", + "labels": [], + "author": "ngyygm" + }, + { + "number": 46, + "title": "npm安装依赖和配置提示project.license` as a TOML table is deprecated", + "url": "https://github.com/666ghj/MiroFish/issues/46", + "created_at": "2026-01-21T12:26:05Z", + "updated_at": "2026-01-23T10:34:52Z", + "labels": [], + "author": "Vamco2022" + }, + { + "number": 45, + "title": "与世界中任意个体对话功能和发送调查问卷到世界中 两个功能报错 IPC 响应 failed", + "url": "https://github.com/666ghj/MiroFish/issues/45", + "created_at": "2026-01-21T06:46:41Z", + "updated_at": "2026-01-21T07:11:18Z", + "labels": [], + "author": "LucasXu666666" + }, + { + "number": 43, + "title": "在使用时调用IPC超时", + "url": "https://github.com/666ghj/MiroFish/issues/43", + "created_at": "2026-01-21T02:23:35Z", + "updated_at": "2026-01-21T07:10:12Z", + "labels": [], + "author": "dbplayer-git" + }, + { + "number": 42, + "title": "项目在3/5开始模拟时会消耗大量内存", + "url": "https://github.com/666ghj/MiroFish/issues/42", + "created_at": "2026-01-21T01:57:50Z", + "updated_at": "2026-03-09T17:28:20Z", + "labels": [], + "author": "s1f102500012" + }, + { + "number": 37, + "title": "模拟环境未运行或已关闭,无法执行Interview: sim_66f01bcf8013。模拟环境可能已关闭,请确保OASIS环境正在运行。", + "url": "https://github.com/666ghj/MiroFish/issues/37", + "created_at": "2026-01-20T09:10:49Z", + "updated_at": "2026-02-09T04:54:14Z", + "labels": [], + "author": "Ezj-Amon" + }, + { + "number": 24, + "title": "ERROR: 报告生成失败: 'NoneType' object is not subscriptable", + "url": "https://github.com/666ghj/MiroFish/issues/24", + "created_at": "2026-01-14T15:53:08Z", + "updated_at": "2026-01-21T13:28:41Z", + "labels": [], + "author": "Joe-rq" + }, + { + "number": 21, + "title": "部署在群辉服务器上,docker里启动了服务,然后用过反向代理可以访问前端了,如果已经开始模拟了,刷新网页或者关掉再打开会发生什么", + "url": "https://github.com/666ghj/MiroFish/issues/21", + "created_at": "2026-01-14T08:33:53Z", + "updated_at": "2026-01-14T08:33:53Z", + "labels": [], + "author": "usernametooshort" + }, + { + "number": 19, + "title": "建议初次使用不用太大的pdf", + "url": "https://github.com/666ghj/MiroFish/issues/19", + "created_at": "2026-01-14T02:45:19Z", + "updated_at": "2026-01-15T05:57:37Z", + "labels": [], + "author": "paperplane123" + }, + { + "number": 17, + "title": "多次仿真 + 元报告共识,提升预测结果的可信度", + "url": "https://github.com/666ghj/MiroFish/issues/17", + "created_at": "2026-01-06T09:07:51Z", + "updated_at": "2026-01-06T09:07:51Z", + "labels": [], + "author": "tt-a1i" + }, + { + "number": 14, + "title": "Frontend doesn't show error when simulation fails", + "url": "https://github.com/666ghj/MiroFish/issues/14", + "created_at": "2026-01-05T11:43:44Z", + "updated_at": "2026-01-06T06:15:22Z", + "labels": [], + "author": "tt-a1i" + }, + { + "number": 9, + "title": "可以设置中断重新加载吗", + "url": "https://github.com/666ghj/MiroFish/issues/9", + "created_at": "2025-12-28T13:16:54Z", + "updated_at": "2026-02-21T09:55:20Z", + "labels": [], + "author": "LMG-arch" + } + ], + "pull_requests": [ + { + "number": 132, + "title": "docs:add simple system architecture part for README-EN.md & README.md", + "url": "https://github.com/666ghj/MiroFish/pull/132", + "created_at": "2026-03-11T05:45:53Z", + "updated_at": "2026-03-11T05:47:00Z", + "head": "docs/add-sys-architecture-part", + "base": "main", + "draft": false, + "author": "Noblegasesgoo" + }, + { + "number": 131, + "title": "feat(graph_builder): add retry mechanism for Zep Cloud connection failures", + "url": "https://github.com/666ghj/MiroFish/pull/131", + "created_at": "2026-03-11T05:42:07Z", + "updated_at": "2026-03-11T05:43:10Z", + "head": "feat/zep-retry-mechanism", + "base": "main", + "draft": false, + "author": "EuanTop" + }, + { + "number": 130, + "title": "docs: 添加贡献指南文档", + "url": "https://github.com/666ghj/MiroFish/pull/130", + "created_at": "2026-03-11T04:24:56Z", + "updated_at": "2026-03-11T04:26:00Z", + "head": "docs/add-pr-guide", + "base": "main", + "draft": false, + "author": "M-Tlinqinming" + }, + { + "number": 129, + "title": "fix(report_agent): handle API token overflow crash with context lengt…", + "url": "https://github.com/666ghj/MiroFish/pull/129", + "created_at": "2026-03-11T02:55:33Z", + "updated_at": "2026-03-11T02:56:38Z", + "head": "fix/fix-priority-issues-mNNjT", + "base": "main", + "draft": false, + "author": "ai-x-builder" + }, + { + "number": 127, + "title": "Fix potential crash in LLMClient when content is None", + "url": "https://github.com/666ghj/MiroFish/pull/127", + "created_at": "2026-03-10T22:43:33Z", + "updated_at": "2026-03-10T22:44:42Z", + "head": "fix/llm-client-none-content", + "base": "main", + "draft": false, + "author": "sjhddh" + }, + { + "number": 126, + "title": "feat: Add custom exceptions and enhanced config validation", + "url": "https://github.com/666ghj/MiroFish/pull/126", + "created_at": "2026-03-10T22:12:22Z", + "updated_at": "2026-03-10T22:13:37Z", + "head": "feature/custom-exceptions-and-config-validation", + "base": "main", + "draft": false, + "author": "ZaviQ7" + }, + { + "number": 125, + "title": "fix: improve new-project network error diagnostics", + "url": "https://github.com/666ghj/MiroFish/pull/125", + "created_at": "2026-03-10T21:50:43Z", + "updated_at": "2026-03-10T21:51:51Z", + "head": "fix/issue-121", + "base": "main", + "draft": false, + "author": "SergioChan" + }, + { + "number": 124, + "title": "fix: robust JSON extraction for mixed LLM responses", + "url": "https://github.com/666ghj/MiroFish/pull/124", + "created_at": "2026-03-10T21:50:31Z", + "updated_at": "2026-03-10T21:51:46Z", + "head": "fix/issue-64", + "base": "main", + "draft": false, + "author": "SergioChan" + }, + { + "number": 122, + "title": "fix(llm_client): remove response_format json_object for local LLM compatibility", + "url": "https://github.com/666ghj/MiroFish/pull/122", + "created_at": "2026-03-10T18:20:49Z", + "updated_at": "2026-03-10T18:33:48Z", + "head": "fix/lm-studio-json-object-compat", + "base": "main", + "draft": false, + "author": "ImL1s" + }, + { + "number": 120, + "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", + "url": "https://github.com/666ghj/MiroFish/pull/120", + "created_at": "2026-03-10T15:41:04Z", + "updated_at": "2026-03-11T03:54:11Z", + "head": "main", + "base": "main", + "draft": false, + "author": "28764116" + }, + { + "number": 119, + "title": "feat: add an option to switch to english language", + "url": "https://github.com/666ghj/MiroFish/pull/119", + "created_at": "2026-03-10T15:05:40Z", + "updated_at": "2026-03-10T18:14:33Z", + "head": "language-option", + "base": "main", + "draft": false, + "author": "Pratiyankkumar" + }, + { + "number": 118, + "title": "feat(ragflow): add RAGflow as alternative graph backend with full pip…", + "url": "https://github.com/666ghj/MiroFish/pull/118", + "created_at": "2026-03-10T09:29:33Z", + "updated_at": "2026-03-10T09:30:44Z", + "head": "fix/ragflow-pattern-compliance", + "base": "main", + "draft": false, + "author": "pratyush618" + }, + { + "number": 116, + "title": "Upgrade GitHub Actions", + "url": "https://github.com/666ghj/MiroFish/pull/116", + "created_at": "2026-03-10T07:30:38Z", + "updated_at": "2026-03-10T07:30:42Z", + "head": "chore/upgrade-actions", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 115, + "title": "Use SPDX license string", + "url": "https://github.com/666ghj/MiroFish/pull/115", + "created_at": "2026-03-10T07:28:37Z", + "updated_at": "2026-03-10T07:28:41Z", + "head": "fix/pyproject-license", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 114, + "title": "Fix API base URL fallback", + "url": "https://github.com/666ghj/MiroFish/pull/114", + "created_at": "2026-03-10T07:21:29Z", + "updated_at": "2026-03-10T07:21:49Z", + "head": "fix/api-baseurl-default", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 113, + "title": "docs(readme): add Japanese README", + "url": "https://github.com/666ghj/MiroFish/pull/113", + "created_at": "2026-03-10T06:43:16Z", + "updated_at": "2026-03-10T06:44:34Z", + "head": "add-ja-doc", + "base": "main", + "draft": false, + "author": "eltociear" + }, + { + "number": 112, + "title": "Korean README.md added", + "url": "https://github.com/666ghj/MiroFish/pull/112", + "created_at": "2026-03-10T05:25:01Z", + "updated_at": "2026-03-10T05:25:55Z", + "head": "main", + "base": "main", + "draft": false, + "author": "waitle" + }, + { + "number": 108, + "title": "feat(installer): add Windows installer build scripts", + "url": "https://github.com/666ghj/MiroFish/pull/108", + "created_at": "2026-03-09T17:14:55Z", + "updated_at": "2026-03-09T17:16:21Z", + "head": "feat/windows-installer", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 105, + "title": "fix: security improvements and error handling fixes", + "url": "https://github.com/666ghj/MiroFish/pull/105", + "created_at": "2026-03-09T11:57:58Z", + "updated_at": "2026-03-11T05:48:53Z", + "head": "fix/security-improvements", + "base": "main", + "draft": false, + "author": "hobostay" + }, + { + "number": 104, + "title": "fix: make vite proxy target configurable via environment variable", + "url": "https://github.com/666ghj/MiroFish/pull/104", + "created_at": "2026-03-09T09:05:37Z", + "updated_at": "2026-03-09T09:06:54Z", + "head": "fix/remove-hardcoded-api-url", + "base": "main", + "draft": false, + "author": "nil957" + }, + { + "number": 103, + "title": "ci: upgrade GitHub Actions and add ARM64 Docker support", + "url": "https://github.com/666ghj/MiroFish/pull/103", + "created_at": "2026-03-09T09:03:45Z", + "updated_at": "2026-03-09T09:04:59Z", + "head": "fix/upgrade-actions-and-arm-support", + "base": "main", + "draft": false, + "author": "nil957" + }, + { + "number": 102, + "title": "fix(ci): add multi-platform Docker build for ARM64 support", + "url": "https://github.com/666ghj/MiroFish/pull/102", + "created_at": "2026-03-09T08:25:27Z", + "updated_at": "2026-03-09T08:26:30Z", + "head": "fix/docker-multiplatform", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 101, + "title": "feat(utils): add json_utils module for robust LLM JSON parsing", + "url": "https://github.com/666ghj/MiroFish/pull/101", + "created_at": "2026-03-09T08:23:07Z", + "updated_at": "2026-03-09T08:24:20Z", + "head": "feat/json-utils-helper", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 100, + "title": "fix(frontend): use relative baseURL in production, avoid hardcoded localhost", + "url": "https://github.com/666ghj/MiroFish/pull/100", + "created_at": "2026-03-09T08:19:23Z", + "updated_at": "2026-03-09T08:20:38Z", + "head": "fix/frontend-baseurl", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 87, + "title": "Upgrade GitHub Actions to latest versions", + "url": "https://github.com/666ghj/MiroFish/pull/87", + "created_at": "2026-03-08T09:09:13Z", + "updated_at": "2026-03-08T09:09:19Z", + "head": "upgrade-github-actions-node24-general", + "base": "main", + "draft": false, + "author": "salmanmkc" + }, + { + "number": 86, + "title": "Upgrade GitHub Actions for Node 24 compatibility", + "url": "https://github.com/666ghj/MiroFish/pull/86", + "created_at": "2026-03-08T09:09:10Z", + "updated_at": "2026-03-08T09:09:14Z", + "head": "upgrade-github-actions-node24", + "base": "main", + "draft": false, + "author": "salmanmkc" + }, + { + "number": 82, + "title": "[Security] Fix CRITICAL vulnerability: CVE-2025-64712", + "url": "https://github.com/666ghj/MiroFish/pull/82", + "created_at": "2026-03-08T02:45:42Z", + "updated_at": "2026-03-08T02:45:46Z", + "head": "fix-cve-2025-64712-unstructured", + "base": "main", + "draft": false, + "author": "orbisai0security" + }, + { + "number": 81, + "title": "feat: add configurable API timeout for slow local LLMs", + "url": "https://github.com/666ghj/MiroFish/pull/81", + "created_at": "2026-03-08T02:34:41Z", + "updated_at": "2026-03-08T02:35:36Z", + "head": "fix/issue-58-configurable-timeout", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 74, + "title": "fix: replace 4 bare excepts with except Exception", + "url": "https://github.com/666ghj/MiroFish/pull/74", + "created_at": "2026-02-25T03:01:43Z", + "updated_at": "2026-02-25T09:20:00Z", + "head": "fix/bare-excepts", + "base": "main", + "draft": false, + "author": "haosenwang1018" + }, + { + "number": 73, + "title": "fix: Handle string entities/edges in _validate_and_process", + "url": "https://github.com/666ghj/MiroFish/pull/73", + "created_at": "2026-02-20T12:41:04Z", + "updated_at": "2026-02-20T12:42:03Z", + "head": "fix-ontology-validation", + "base": "main", + "draft": false, + "author": "calvinguo721" + }, + { + "number": 72, + "title": "清理模型返回的markdown标记", + "url": "https://github.com/666ghj/MiroFish/pull/72", + "created_at": "2026-02-15T05:27:05Z", + "updated_at": "2026-03-10T02:58:45Z", + "head": "main", + "base": "main", + "draft": false, + "author": "MoeclubM" + }, + { + "number": 70, + "title": "windows安装程序打包", + "url": "https://github.com/666ghj/MiroFish/pull/70", + "created_at": "2026-02-10T14:47:00Z", + "updated_at": "2026-02-16T20:17:26Z", + "head": "main", + "base": "main", + "draft": false, + "author": "Jonah-Wu23" + }, + { + "number": 49, + "title": "记忆图谱本地化实现", + "url": "https://github.com/666ghj/MiroFish/pull/49", + "created_at": "2026-01-22T06:42:21Z", + "updated_at": "2026-01-22T06:42:21Z", + "head": "feat/local", + "base": "main", + "draft": false, + "author": "Momoyeyu" + }, + { + "number": 38, + "title": "feat: Add support for Anthropic SDK (Claude) and multi-provider switching", + "url": "https://github.com/666ghj/MiroFish/pull/38", + "created_at": "2026-01-20T09:56:00Z", + "updated_at": "2026-01-24T16:25:40Z", + "head": "feat/anthropic-sdk", + "base": "main", + "draft": false, + "author": "SmartisanNaive" + }, + { + "number": 15, + "title": "fix(frontend): handle simulation failed status", + "url": "https://github.com/666ghj/MiroFish/pull/15", + "created_at": "2026-01-06T06:45:39Z", + "updated_at": "2026-01-06T06:53:51Z", + "head": "fix/frontend-simulation-error-handling", + "base": "main", + "draft": false, + "author": "tt-a1i" + } + ] +} diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index e822b8f7..3365aff6 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -1,7 +1,7 @@ # Upstream Triage Snapshot - Repository: `666ghj/MiroFish` -- Captured: `2026-03-11T06:28:09.817366+00:00` +- Captured: `2026-03-11T06:33:02.083380+00:00` - Open issues: `32` - Open pull requests: `35` diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index afcdeefe..5bd8da7b 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -8,13 +8,27 @@ Last refreshed: `2026-03-11` - Land small, low-risk upstream fixes before considering larger feature branches. - Make backend compatibility with OpenAI-compatible providers explicit in code and docs. -## Safe PR candidates reviewed +## Landed on this branch - `#115` Use SPDX license string: safe metadata-only cherry-pick. +- `#116` Upgrade GitHub Actions: safe workflow-only dependency bump. +- `#125` Improve new-project network error diagnostics: safe single-file frontend error-message improvement. - `#122` Remove `response_format={"type":"json_object"}` from `chat_json()`: improves compatibility with LM Studio and Ollama-style backends. - `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. - `#127` Handle `None` response content: safe guard against provider edge cases. +## Deferred for later review + +- `#131` Zep retry mechanism: relevant to rate-limit and transient-connectivity issues, but broader behavioral change than the already-landed fixes and should be validated with targeted backend tests first. +- `#105` Security and error-handling sweep: high-value, but touches multiple API surfaces and config defaults, so it needs a dedicated pass instead of bundling into a low-risk cherry-pick cycle. +- `#129` Report-agent token overflow handling: promising, but it touches report-generation flow and should be evaluated with reproducible fixtures before merging. + +## Validation status + +- `cd frontend && npm run build` passes after landing `#125`. +- `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. +- Follow-up is tracked in local beads issue `mirofish-ba6` to establish a lighter backend validation path. + ## Practical mirror strategy for the fork - Mirror the highest-signal upstream PR branches to the fork when they are under active review. From 34e2012d6639b0b56a42043da8c47e850e7cea01 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:36:43 +0000 Subject: [PATCH 007/373] feat(frontend): support configurable API timeout --- .env.example | 4 ++++ docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 1 + frontend/src/api/index.js | 7 ++++++- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 3280a6de..430816c3 100644 --- a/.env.example +++ b/.env.example @@ -15,3 +15,7 @@ ZEP_API_KEY=your_zep_api_key_here LLM_BOOST_API_KEY=your_api_key_here LLM_BOOST_BASE_URL=your_base_url_here LLM_BOOST_MODEL_NAME=your_model_name_here + +# ===== 前端 API 超时配置(可选)===== +# 本地大模型响应较慢时可以增加此值(毫秒) +# VITE_API_TIMEOUT=600000 diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index d050523a..24f515d9 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:33:02.082890+00:00", + "captured_at": "2026-03-11T06:35:18.158536+00:00", "issues": [ { "number": 117, diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 3365aff6..a01af946 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -1,7 +1,7 @@ # Upstream Triage Snapshot - Repository: `666ghj/MiroFish` -- Captured: `2026-03-11T06:33:02.083380+00:00` +- Captured: `2026-03-11T06:35:18.158999+00:00` - Open issues: `32` - Open pull requests: `35` diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 5bd8da7b..dc8bb747 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -10,6 +10,7 @@ Last refreshed: `2026-03-11` ## Landed on this branch +- `#81` Configurable frontend API timeout: low-risk support for slow local/OpenAI-compatible backends such as Ollama. - `#115` Use SPDX license string: safe metadata-only cherry-pick. - `#116` Upgrade GitHub Actions: safe workflow-only dependency bump. - `#125` Improve new-project network error diagnostics: safe single-file frontend error-message improvement. diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index ca932dc9..b45ab5dd 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -13,10 +13,15 @@ const resolveBaseURL = () => { return '' } +const resolveTimeout = () => { + const envTimeout = Number.parseInt(import.meta.env.VITE_API_TIMEOUT, 10) + return Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 300000 +} + // 创建axios实例 const service = axios.create({ baseURL: resolveBaseURL(), - timeout: 300000, // 5分钟超时(本体生成可能需要较长时间) + timeout: resolveTimeout(), // 可配置超时时间,默认5分钟(本地大模型可能需要更长时间) headers: { 'Content-Type': 'application/json' } From e86b8ba1e86395f77a3dcd2d13b718762c5131a7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:41:32 +0000 Subject: [PATCH 008/373] fix: harden llm context handling --- .env.example | 3 ++ README-EN.md | 2 + README.md | 2 + backend/app/config.py | 1 + backend/app/services/report_agent.py | 10 ++++ backend/app/utils/llm_client.py | 62 ++++++++++++++++++++-- backend/scripts/run_parallel_simulation.py | 10 ++-- backend/scripts/run_reddit_simulation.py | 15 +++--- backend/scripts/run_twitter_simulation.py | 14 ++--- backend/tests/test_llm_client.py | 60 +++++++++++++++++++++ docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 7 +-- 13 files changed, 160 insertions(+), 30 deletions(-) diff --git a/.env.example b/.env.example index 430816c3..576afe90 100644 --- a/.env.example +++ b/.env.example @@ -2,9 +2,12 @@ # 也兼容标准 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL 环境变量 # 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/ # 注意消耗较大,可先进行小于40轮的模拟尝试 +# 如果你已经有 OpenAI / Codex 兼容网关,也可以只设置 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL LLM_API_KEY=your_api_key_here LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 LLM_MODEL_NAME=qwen-plus +# 上下文窗口较小的模型可以降低单次输出上限,避免 report agent 触发 token overflow +# LLM_MAX_TOKENS=4096 # ===== ZEP记忆图谱配置 ===== # 每月免费额度即可支撑简单使用:https://app.getzep.com/ diff --git a/README-EN.md b/README-EN.md index f4a1b57c..ca165f9a 100644 --- a/README-EN.md +++ b/README-EN.md @@ -122,6 +122,8 @@ cp .env.example .env LLM_API_KEY=your_api_key LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 LLM_MODEL_NAME=qwen-plus +# Optional: reduce this for OpenAI-compatible backends with smaller context windows +# LLM_MAX_TOKENS=4096 # Zep Cloud Configuration # Free monthly quota is sufficient for simple usage: https://app.getzep.com/ diff --git a/README.md b/README.md index 347d7fa3..8b224dcb 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ cp .env.example .env LLM_API_KEY=your_api_key LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 LLM_MODEL_NAME=qwen-plus +# 可选:上下文较小的 OpenAI-compatible 模型可降低输出上限 +# LLM_MAX_TOKENS=4096 # Zep Cloud 配置 # 每月免费额度即可支撑简单使用:https://app.getzep.com/ diff --git a/backend/app/config.py b/backend/app/config.py index 5da36bb3..451c258d 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -40,6 +40,7 @@ class Config: LLM_API_KEY = _env('LLM_API_KEY', 'OPENAI_API_KEY') LLM_BASE_URL = _env('LLM_BASE_URL', 'OPENAI_BASE_URL', default='https://api.openai.com/v1') LLM_MODEL_NAME = _env('LLM_MODEL_NAME', 'OPENAI_MODEL', default='gpt-4o-mini') + LLM_MAX_TOKENS = int(os.environ.get('LLM_MAX_TOKENS', '4096')) # Zep配置 ZEP_API_KEY = os.environ.get('ZEP_API_KEY') diff --git a/backend/app/services/report_agent.py b/backend/app/services/report_agent.py index 02ca5bdc..49cb42e4 100644 --- a/backend/app/services/report_agent.py +++ b/backend/app/services/report_agent.py @@ -879,6 +879,13 @@ class ReportAgent: # 对话中的最大工具调用次数 MAX_TOOL_CALLS_PER_CHAT = 2 + + @staticmethod + def _prune_messages_for_retry(messages: List[Dict[str, str]]) -> List[Dict[str, str]]: + """Keep the initial prompt and latest turns to avoid unbounded context growth.""" + if len(messages) <= 14: + return messages + return messages[:2] + messages[-12:] def __init__( self, @@ -1298,6 +1305,8 @@ def _generate_section_react( int((iteration / max_iterations) * 100), f"深度检索与撰写中 ({tool_calls_count}/{self.MAX_TOOL_CALLS_PER_SECTION})" ) + + messages = self._prune_messages_for_retry(messages) # 调用LLM response = self.llm.chat( @@ -1502,6 +1511,7 @@ def _generate_section_react( # 达到最大迭代次数,强制生成内容 logger.warning(f"章节 {section.title} 达到最大迭代次数,强制生成") messages.append({"role": "user", "content": REACT_FORCE_FINAL_MSG}) + messages = self._prune_messages_for_retry(messages) response = self.llm.chat( messages=messages, diff --git a/backend/app/utils/llm_client.py b/backend/app/utils/llm_client.py index dd539175..c3fe4a38 100644 --- a/backend/app/utils/llm_client.py +++ b/backend/app/utils/llm_client.py @@ -4,12 +4,15 @@ """ import json +import logging import re from typing import Optional, Dict, Any, List -from openai import OpenAI +from openai import OpenAI, APIError, BadRequestError from ..config import Config +logger = logging.getLogger(__name__) + class LLMClient: """LLM客户端""" @@ -23,6 +26,7 @@ def __init__( self.api_key = api_key or Config.LLM_API_KEY self.base_url = base_url or Config.LLM_BASE_URL self.model = model or Config.LLM_MODEL_NAME + self.default_max_tokens = Config.LLM_MAX_TOKENS if not self.api_key: raise ValueError("LLM_API_KEY / OPENAI_API_KEY 未配置") @@ -31,12 +35,41 @@ def __init__( api_key=self.api_key, base_url=self.base_url ) + + @staticmethod + def _trim_messages(messages: List[Dict[str, str]]) -> List[Dict[str, str]]: + """Trim old context while preserving the initial prompt and recent turns.""" + if len(messages) <= 8: + return messages + + head_count = 2 if len(messages) >= 2 else 1 + tail_count = min(8, len(messages) - head_count) + tail_start = max(head_count, len(messages) - tail_count) + trimmed = messages[:head_count] + messages[tail_start:] + + if len(trimmed) < len(messages): + logger.warning("Trimmed LLM context from %s to %s messages", len(messages), len(trimmed)) + + return trimmed + + @staticmethod + def _is_context_length_error(exc: Exception) -> bool: + text = str(exc).lower() + markers = ( + "context_length", + "maximum context", + "context window", + "too many tokens", + "maximum tokens", + "token limit", + ) + return any(marker in text for marker in markers) def chat( self, messages: List[Dict[str, str]], temperature: float = 0.7, - max_tokens: int = 4096, + max_tokens: Optional[int] = None, response_format: Optional[Dict] = None ) -> str: """ @@ -51,6 +84,9 @@ def chat( Returns: 模型响应文本 """ + if max_tokens is None: + max_tokens = self.default_max_tokens + kwargs = { "model": self.model, "messages": messages, @@ -60,8 +96,24 @@ def chat( if response_format: kwargs["response_format"] = response_format - - response = self.client.chat.completions.create(**kwargs) + + try: + response = self.client.chat.completions.create(**kwargs) + except BadRequestError as exc: + if not self._is_context_length_error(exc): + raise + + trimmed_messages = self._trim_messages(messages) + if len(trimmed_messages) == len(messages): + raise + + logger.warning("Retrying LLM call after context-length failure") + kwargs["messages"] = trimmed_messages + response = self.client.chat.completions.create(**kwargs) + except APIError: + logger.exception("LLM API request failed") + raise + content = response.choices[0].message.content or "" # 部分模型会在 content 中夹带 ...,且标签大小写不固定 content = re.sub(r']*>[\s\S]*?', '', content, flags=re.IGNORECASE).strip() @@ -98,7 +150,7 @@ def chat_json( self, messages: List[Dict[str, str]], temperature: float = 0.3, - max_tokens: int = 4096 + max_tokens: Optional[int] = None ) -> Dict[str, Any]: """ 发送聊天请求并返回JSON diff --git a/backend/scripts/run_parallel_simulation.py b/backend/scripts/run_parallel_simulation.py index 2a627ffd..30c13124 100644 --- a/backend/scripts/run_parallel_simulation.py +++ b/backend/scripts/run_parallel_simulation.py @@ -986,7 +986,7 @@ def create_model(config: Dict[str, Any], use_boost: bool = False): 创建LLM模型 支持双 LLM 配置,用于并行模拟时提速: - - 通用配置:LLM_API_KEY, LLM_BASE_URL, LLM_MODEL_NAME + - 通用配置:LLM_API_KEY / OPENAI_API_KEY, LLM_BASE_URL / OPENAI_BASE_URL, LLM_MODEL_NAME / OPENAI_MODEL - 加速配置(可选):LLM_BOOST_API_KEY, LLM_BOOST_BASE_URL, LLM_BOOST_MODEL_NAME 如果配置了加速 LLM,并行模拟时可以让不同平台使用不同的 API 服务商,提高并发能力。 @@ -1010,9 +1010,9 @@ def create_model(config: Dict[str, Any], use_boost: bool = False): config_label = "[加速LLM]" else: # 使用通用配置 - llm_api_key = os.environ.get("LLM_API_KEY", "") - llm_base_url = os.environ.get("LLM_BASE_URL", "") - llm_model = os.environ.get("LLM_MODEL_NAME", "") + llm_api_key = os.environ.get("LLM_API_KEY") or os.environ.get("OPENAI_API_KEY", "") + llm_base_url = os.environ.get("LLM_BASE_URL") or os.environ.get("OPENAI_BASE_URL", "") + llm_model = os.environ.get("LLM_MODEL_NAME") or os.environ.get("OPENAI_MODEL", "") config_label = "[通用LLM]" # 如果 .env 中没有模型名,则使用 config 作为备用 @@ -1024,7 +1024,7 @@ def create_model(config: Dict[str, Any], use_boost: bool = False): os.environ["OPENAI_API_KEY"] = llm_api_key if not os.environ.get("OPENAI_API_KEY"): - raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY") + raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY 或 OPENAI_API_KEY") if llm_base_url: os.environ["OPENAI_API_BASE_URL"] = llm_base_url diff --git a/backend/scripts/run_reddit_simulation.py b/backend/scripts/run_reddit_simulation.py index 14907cbd..6047678e 100644 --- a/backend/scripts/run_reddit_simulation.py +++ b/backend/scripts/run_reddit_simulation.py @@ -436,14 +436,14 @@ def _create_model(self): 创建LLM模型 统一使用项目根目录 .env 文件中的配置(优先级最高): - - LLM_API_KEY: API密钥 - - LLM_BASE_URL: API基础URL - - LLM_MODEL_NAME: 模型名称 + - LLM_API_KEY / OPENAI_API_KEY: API密钥 + - LLM_BASE_URL / OPENAI_BASE_URL: API基础URL + - LLM_MODEL_NAME / OPENAI_MODEL: 模型名称 """ # 优先从 .env 读取配置 - llm_api_key = os.environ.get("LLM_API_KEY", "") - llm_base_url = os.environ.get("LLM_BASE_URL", "") - llm_model = os.environ.get("LLM_MODEL_NAME", "") + llm_api_key = os.environ.get("LLM_API_KEY") or os.environ.get("OPENAI_API_KEY", "") + llm_base_url = os.environ.get("LLM_BASE_URL") or os.environ.get("OPENAI_BASE_URL", "") + llm_model = os.environ.get("LLM_MODEL_NAME") or os.environ.get("OPENAI_MODEL", "") # 如果 .env 中没有,则使用 config 作为备用 if not llm_model: @@ -454,7 +454,7 @@ def _create_model(self): os.environ["OPENAI_API_KEY"] = llm_api_key if not os.environ.get("OPENAI_API_KEY"): - raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY") + raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY 或 OPENAI_API_KEY") if llm_base_url: os.environ["OPENAI_API_BASE_URL"] = llm_base_url @@ -766,4 +766,3 @@ def signal_handler(signum, frame): pass finally: print("模拟进程已退出") - diff --git a/backend/scripts/run_twitter_simulation.py b/backend/scripts/run_twitter_simulation.py index caab9e9d..18d49963 100644 --- a/backend/scripts/run_twitter_simulation.py +++ b/backend/scripts/run_twitter_simulation.py @@ -429,14 +429,14 @@ def _create_model(self): 创建LLM模型 统一使用项目根目录 .env 文件中的配置(优先级最高): - - LLM_API_KEY: API密钥 - - LLM_BASE_URL: API基础URL - - LLM_MODEL_NAME: 模型名称 + - LLM_API_KEY / OPENAI_API_KEY: API密钥 + - LLM_BASE_URL / OPENAI_BASE_URL: API基础URL + - LLM_MODEL_NAME / OPENAI_MODEL: 模型名称 """ # 优先从 .env 读取配置 - llm_api_key = os.environ.get("LLM_API_KEY", "") - llm_base_url = os.environ.get("LLM_BASE_URL", "") - llm_model = os.environ.get("LLM_MODEL_NAME", "") + llm_api_key = os.environ.get("LLM_API_KEY") or os.environ.get("OPENAI_API_KEY", "") + llm_base_url = os.environ.get("LLM_BASE_URL") or os.environ.get("OPENAI_BASE_URL", "") + llm_model = os.environ.get("LLM_MODEL_NAME") or os.environ.get("OPENAI_MODEL", "") # 如果 .env 中没有,则使用 config 作为备用 if not llm_model: @@ -447,7 +447,7 @@ def _create_model(self): os.environ["OPENAI_API_KEY"] = llm_api_key if not os.environ.get("OPENAI_API_KEY"): - raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY") + raise ValueError("缺少 API Key 配置,请在项目根目录 .env 文件中设置 LLM_API_KEY 或 OPENAI_API_KEY") if llm_base_url: os.environ["OPENAI_API_BASE_URL"] = llm_base_url diff --git a/backend/tests/test_llm_client.py b/backend/tests/test_llm_client.py index 05cf2b76..da412ba3 100644 --- a/backend/tests/test_llm_client.py +++ b/backend/tests/test_llm_client.py @@ -65,3 +65,63 @@ def __init__(self, api_key, base_url): assert response == {"ok": True} assert "response_format" not in create_calls[0] + + +def test_chat_retries_with_trimmed_messages_on_context_length_error(monkeypatch): + create_calls = [] + + class FakeBadRequestError(Exception): + pass + + class FakeCompletions: + def create(self, **kwargs): + create_calls.append(kwargs) + if len(create_calls) == 1: + raise FakeBadRequestError("context_length exceeded") + return SimpleNamespace( + choices=[SimpleNamespace(message=SimpleNamespace(content="trimmed response"))] + ) + + class FakeOpenAI: + def __init__(self, api_key, base_url): + self.chat = SimpleNamespace(completions=FakeCompletions()) + + monkeypatch.setattr("app.utils.llm_client.OpenAI", FakeOpenAI) + monkeypatch.setattr("app.utils.llm_client.BadRequestError", FakeBadRequestError) + + client = LLMClient(api_key="test-key", base_url="https://example.test/v1", model="test-model") + messages = [{"role": "system", "content": "system"}, {"role": "user", "content": "user"}] + messages.extend( + {"role": "assistant" if i % 2 == 0 else "user", "content": f"message-{i}"} + for i in range(12) + ) + + response = client.chat(messages) + + assert response == "trimmed response" + assert len(create_calls) == 2 + assert len(create_calls[1]["messages"]) < len(messages) + assert create_calls[1]["messages"][:2] == messages[:2] + + +def test_chat_uses_configured_default_max_tokens(monkeypatch): + create_calls = [] + + class FakeCompletions: + def create(self, **kwargs): + create_calls.append(kwargs) + return SimpleNamespace( + choices=[SimpleNamespace(message=SimpleNamespace(content="ok"))] + ) + + class FakeOpenAI: + def __init__(self, api_key, base_url): + self.chat = SimpleNamespace(completions=FakeCompletions()) + + monkeypatch.setattr("app.utils.llm_client.OpenAI", FakeOpenAI) + monkeypatch.setattr("app.utils.llm_client.Config.LLM_MAX_TOKENS", 1234) + + client = LLMClient(api_key="test-key", base_url="https://example.test/v1", model="test-model") + client.chat([{"role": "user", "content": "hello"}]) + + assert create_calls[0]["max_tokens"] == 1234 diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 24f515d9..677a7124 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:35:18.158536+00:00", + "captured_at": "2026-03-11T06:38:00.348727+00:00", "issues": [ { "number": 117, diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index a01af946..9d3d2df0 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -1,7 +1,7 @@ # Upstream Triage Snapshot - Repository: `666ghj/MiroFish` -- Captured: `2026-03-11T06:35:18.158999+00:00` +- Captured: `2026-03-11T06:38:00.349207+00:00` - Open issues: `32` - Open pull requests: `35` diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index dc8bb747..481cd439 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -17,16 +17,17 @@ Last refreshed: `2026-03-11` - `#122` Remove `response_format={"type":"json_object"}` from `chat_json()`: improves compatibility with LM Studio and Ollama-style backends. - `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. - `#127` Handle `None` response content: safe guard against provider edge cases. +- `#129` Safe subset landed locally: configurable `LLM_MAX_TOKENS`, automatic retry after context-length failures, and report-agent message pruning to reduce overflow crashes. +- OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. ## Deferred for later review - `#131` Zep retry mechanism: relevant to rate-limit and transient-connectivity issues, but broader behavioral change than the already-landed fixes and should be validated with targeted backend tests first. - `#105` Security and error-handling sweep: high-value, but touches multiple API surfaces and config defaults, so it needs a dedicated pass instead of bundling into a low-risk cherry-pick cycle. -- `#129` Report-agent token overflow handling: promising, but it touches report-generation flow and should be evaluated with reproducible fixtures before merging. - ## Validation status -- `cd frontend && npm run build` passes after landing `#125`. +- `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. +- `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py -q` passes with targeted regression coverage for context-length retry and default token configuration. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. - Follow-up is tracked in local beads issue `mirofish-ba6` to establish a lighter backend validation path. From 11c117e3c64fd77516469347a7b461d1da3780f3 Mon Sep 17 00:00:00 2001 From: Martin Lin <394719020@qq.com> Date: Wed, 11 Mar 2026 12:18:26 +0800 Subject: [PATCH 009/373] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E6=8C=87=E5=8D=97=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 32d0571fd7bd59fae341a98cc63f7991409d8a9b) --- CONTRIBUTING.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0ad9f9e4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# 贡献指南 + +感谢你对 MiroFish 项目的兴趣!我们欢迎任何形式的贡献。 + +## 如何贡献 + +### 1. Fork 仓库 +点击 GitHub 仓库页面的 "Fork" 按钮,将仓库复制到你的账户。 + +### 2. 克隆你的 Fork +```bash +git clone https://github.com/你的用户名/MiroFish.git +cd MiroFish +``` + +### 3. 创建分支 +```bash +git checkout -b feature/你的功能名称 +# 或 +git checkout -b fix/问题描述 +``` + +### 4. 进行修改 +- 确保代码符合项目规范 +- 添加必要的测试 +- 更新相关文档 + +### 5. 提交更改 +```bash +git add . +git commit -m "描述你的修改" +``` + +### 6. 推送到你的 Fork +```bash +git push -u origin docs/add-pr-guide +``` + +### 7. 创建 Pull Request +1. 访问你的 GitHub Fork 仓库 +2. 点击 "Compare & pull request" 按钮 +3. 填写 PR 描述 +4. 点击 "Create pull request" + +## 分支命名规范 + +- `feature/` - 新功能 +- `fix/` - Bug 修复 +- `docs/` - 文档更新 +- `refactor/` - 代码重构 + +## 代码规范 + +- 前端: 遵循 Vue.js 风格指南 +- 后端: 遵循 PEP 8 Python 代码规范 + +## 许可证 + +参与本项目即表示你同意遵守 MIT 许可证。 From c5ae342fbf19f06182891b7dc57e61891cb94fe1 Mon Sep 17 00:00:00 2001 From: noblegasesgoo Date: Wed, 11 Mar 2026 13:39:59 +0800 Subject: [PATCH 010/373] docs:add simple system architecture part for README-EN.md & README.md (cherry picked from commit a9d1c4839a23e6027b49d89af77728ab32cda167) --- README-EN.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) diff --git a/README-EN.md b/README-EN.md index ca165f9a..faa6ba6d 100644 --- a/README-EN.md +++ b/README-EN.md @@ -91,6 +91,113 @@ Click the image to watch MiroFish's deep prediction of the lost ending based on 4. **Report Generation**: ReportAgent with rich toolset for deep interaction with post-simulation environment 5. **Deep Interaction**: Chat with any agent in the simulated world & Interact with ReportAgent +## 🏗️ System Architecture + +### Layer Breakdown + +| Layer | Core Modules | Responsibilities | +|------|--------------|------------------| +| Presentation | `frontend/src/views/*`, `frontend/src/components/*` | 5-step workflow UI, live simulation status, report and interaction pages | +| API | `backend/app/api/graph.py`, `simulation.py`, `report.py` | Public APIs for graph build, simulation control, report generation and download | +| Orchestration | `simulation_manager.py`, `simulation_runner.py` | Simulation state machine, process lifecycle, pause/resume/stop, live status aggregation | +| Memory & Graph | `graph_builder.py`, `zep_entity_reader.py`, `zep_graph_memory_updater.py` | Seed structuring, graph writing, entity filtering, and post-simulation memory writeback | +| Reasoning & Report | `report_agent.py`, `zep_tools.py`, `utils/llm_client.py` | ReACT multi-step reasoning, tool calls, and interactive prediction report generation | + +### Project Code Structure Tree + +```text +MiroFish/ +├── frontend/ # Vue3 frontend project +│ ├── package.json # frontend dependencies and scripts +│ ├── vite.config.js # Vite build/dev server config +│ ├── index.html # frontend HTML entry +│ └── src/ +│ ├── main.js # Vue app bootstrap +│ ├── App.vue # root component +│ ├── api/ # backend API wrappers +│ │ ├── index.js # Axios instance and shared request config +│ │ ├── graph.js # graph build related APIs +│ │ ├── simulation.js # simulation control APIs +│ │ └── report.js # report generation/download/chat APIs +│ ├── router/ +│ │ └── index.js # frontend routes +│ ├── store/ +│ │ └── pendingUpload.js # pending upload state store +│ ├── views/ # page-level views +│ │ ├── Home.vue # home page +│ │ ├── MainView.vue # main workflow container +│ │ ├── Process.vue # 5-step process page +│ │ ├── SimulationView.vue # simulation preparation page +│ │ ├── SimulationRunView.vue # live simulation monitor page +│ │ ├── ReportView.vue # report viewer page +│ │ └── InteractionView.vue # deep interaction page +│ ├── components/ # business components +│ │ ├── Step1GraphBuild.vue # Step1 graph build component +│ │ ├── Step2EnvSetup.vue # Step2 environment setup component +│ │ ├── Step3Simulation.vue # Step3 simulation component +│ │ ├── Step4Report.vue # Step4 report component +│ │ ├── Step5Interaction.vue # Step5 interaction component +│ │ ├── GraphPanel.vue # graph data panel +│ │ └── HistoryDatabase.vue # historical memory/data panel +│ └── assets/logo/ # frontend logo assets +│ ├── MiroFish_logo_left.jpeg +│ └── MiroFish_logo_compressed.jpeg +├── backend/ # Flask backend project +│ ├── run.py # backend service entrypoint +│ ├── requirements.txt # Python dependency list +│ ├── pyproject.toml # Python project metadata/tooling +│ ├── uv.lock # uv-locked dependency versions +│ ├── app/ +│ │ ├── __init__.py # Flask app factory and blueprint wiring +│ │ ├── config.py # backend config and env loading +│ │ ├── api/ # API route layer +│ │ │ ├── __init__.py # Blueprint initialization +│ │ │ ├── graph.py # graph build and graph management endpoints +│ │ │ ├── simulation.py # entity read, simulation create/run/control endpoints +│ │ │ └── report.py # report generate/query/download/chat endpoints +│ │ ├── services/ # core business services +│ │ │ ├── graph_builder.py # GraphRAG graph build service +│ │ │ ├── ontology_generator.py # ontology/entity type generation +│ │ │ ├── text_processor.py # seed text cleaning/preprocessing +│ │ │ ├── zep_entity_reader.py # Zep graph entity read/filter service +│ │ │ ├── oasis_profile_generator.py # OASIS persona/profile generation +│ │ │ ├── simulation_config_generator.py # simulation config auto-generation +│ │ │ ├── simulation_manager.py # simulation lifecycle state manager +│ │ │ ├── simulation_runner.py # background simulation execution/monitoring +│ │ │ ├── simulation_ipc.py # simulation process IPC protocol +│ │ │ ├── zep_graph_memory_updater.py # write simulation actions back to graph memory +│ │ │ ├── zep_tools.py # ReportAgent tool integrations +│ │ │ └── report_agent.py # ReACT report generation and Q&A service +│ │ ├── models/ # state model layer +│ │ │ ├── __init__.py +│ │ │ ├── project.py # project state and metadata manager +│ │ │ └── task.py # async task state model +│ │ └── utils/ # shared infrastructure utilities +│ │ ├── __init__.py +│ │ ├── llm_client.py # OpenAI-SDK-compatible LLM client +│ │ ├── file_parser.py # uploaded file parsing utilities +│ │ ├── logger.py # layered logging system +│ │ ├── retry.py # retry helpers/decorators +│ │ └── zep_paging.py # Zep paging helper +│ ├── scripts/ # OASIS runtime scripts +│ │ ├── run_parallel_simulation.py # Twitter + Reddit parallel simulation entry +│ │ ├── run_twitter_simulation.py # Twitter simulation runner +│ │ ├── run_reddit_simulation.py # Reddit simulation runner +│ │ ├── action_logger.py # agent action logging utility +│ │ └── test_profile_format.py # profile format validation script +│ ├── uploads/ # runtime data (projects/simulations/reports) +│ └── logs/ # backend runtime logs +├── static/ +│ └── image/ # README images and demo assets +├── package.json # root-level scripts for frontend/backend +├── docker-compose.yml # Docker orchestration (frontend + backend) +├── Dockerfile # Docker image build definition +├── .env.example # environment variable template +├── README.md # Chinese documentation +├── README-EN.md # English documentation +└── LICENSE # open-source license +``` + ## 🚀 Quick Start ### Option 1: Source Code Deployment (Recommended) diff --git a/README.md b/README.md index 8b224dcb..66b17479 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,113 @@ MiroFish 致力于打造映射现实的群体智能镜像,通过捕捉个体 4. **报告生成**:ReportAgent拥有丰富的工具集与模拟后环境进行深度交互 5. **深度互动**:与模拟世界中的任意一位进行对话 & 与ReportAgent进行对话 +## 🏗️ 系统架构 + +### 分层说明 + +| 层级 | 核心模块 | 职责 | +|------|----------|------| +| 表现层 | `frontend/src/views/*`、`frontend/src/components/*` | 五步流程 UI、实时模拟状态展示、报告与深度交互页面 | +| API 层 | `backend/app/api/graph.py`、`simulation.py`、`report.py` | 对外提供图谱构建、模拟控制、报告生成与下载接口 | +| 编排层 | `simulation_manager.py`、`simulation_runner.py` | 模拟状态机、进程管理、暂停/恢复/停止与实时状态汇总 | +| 记忆与图谱层 | `graph_builder.py`、`zep_entity_reader.py`、`zep_graph_memory_updater.py` | 种子数据结构化、图谱写入、实体过滤与模拟后记忆回灌 | +| 推理与报告层 | `report_agent.py`、`zep_tools.py`、`utils/llm_client.py` | ReACT 多轮推理、工具调用、自动生成可交互预测报告 | + +### 项目代码结构树 + +```text +MiroFish/ +├── frontend/ # Vue3 前端工程 +│ ├── package.json # 前端依赖与脚本定义 +│ ├── vite.config.js # Vite 构建与开发服务配置 +│ ├── index.html # 前端入口 HTML 模板 +│ └── src/ +│ ├── main.js # Vue 应用启动入口 +│ ├── App.vue # 根组件 +│ ├── api/ # 后端接口封装层 +│ │ ├── index.js # Axios 实例与统一请求配置 +│ │ ├── graph.js # 图谱构建相关 API +│ │ ├── simulation.js # 模拟流程控制 API +│ │ └── report.js # 报告生成/下载/对话 API +│ ├── router/ +│ │ └── index.js # 前端路由配置 +│ ├── store/ +│ │ └── pendingUpload.js # 待上传文件状态管理 +│ ├── views/ # 页面级视图 +│ │ ├── Home.vue # 首页(项目介绍与入口) +│ │ ├── MainView.vue # 主流程容器页 +│ │ ├── Process.vue # 五步流程总览页 +│ │ ├── SimulationView.vue # 模拟准备页 +│ │ ├── SimulationRunView.vue # 模拟运行监控页 +│ │ ├── ReportView.vue # 报告查看页 +│ │ └── InteractionView.vue # 深度交互页 +│ ├── components/ # 业务组件 +│ │ ├── Step1GraphBuild.vue # Step1 图谱构建组件 +│ │ ├── Step2EnvSetup.vue # Step2 环境搭建组件 +│ │ ├── Step3Simulation.vue # Step3 模拟控制组件 +│ │ ├── Step4Report.vue # Step4 报告生成组件 +│ │ ├── Step5Interaction.vue # Step5 深度交互组件 +│ │ ├── GraphPanel.vue # 图谱数据展示面板 +│ │ └── HistoryDatabase.vue # 历史数据/记忆展示组件 +│ └── assets/logo/ # 前端 Logo 资源 +│ ├── MiroFish_logo_left.jpeg +│ └── MiroFish_logo_compressed.jpeg +├── backend/ # Flask 后端工程 +│ ├── run.py # 后端服务启动入口 +│ ├── requirements.txt # Python 依赖清单 +│ ├── pyproject.toml # Python 项目元数据与工具配置 +│ ├── uv.lock # uv 锁定依赖版本 +│ ├── app/ +│ │ ├── __init__.py # Flask 应用工厂与蓝图注册 +│ │ ├── config.py # 后端配置与环境变量读取 +│ │ ├── api/ # API 路由层 +│ │ │ ├── __init__.py # Blueprint 初始化 +│ │ │ ├── graph.py # 图谱构建与图谱管理接口 +│ │ │ ├── simulation.py # 实体读取、模拟创建/运行/控制接口 +│ │ │ └── report.py # 报告生成、查询、下载与问答接口 +│ │ ├── services/ # 核心业务服务层 +│ │ │ ├── graph_builder.py # GraphRAG 图谱构建服务 +│ │ │ ├── ontology_generator.py # 本体/实体类型生成服务 +│ │ │ ├── text_processor.py # 种子文本清洗与预处理 +│ │ │ ├── zep_entity_reader.py # Zep 图谱实体读取与过滤 +│ │ │ ├── oasis_profile_generator.py # OASIS 角色画像生成 +│ │ │ ├── simulation_config_generator.py # 模拟配置自动生成 +│ │ │ ├── simulation_manager.py # 模拟状态机与生命周期管理 +│ │ │ ├── simulation_runner.py # 后台模拟进程执行与监控 +│ │ │ ├── simulation_ipc.py # 模拟进程 IPC 通信协议 +│ │ │ ├── zep_graph_memory_updater.py # 模拟动作回写图谱记忆 +│ │ │ ├── zep_tools.py # ReportAgent 可调用的检索工具集 +│ │ │ └── report_agent.py # ReACT 报告生成与交互问答 +│ │ ├── models/ # 状态模型层 +│ │ │ ├── __init__.py +│ │ │ ├── project.py # 项目状态与元数据管理 +│ │ │ └── task.py # 异步任务状态模型 +│ │ └── utils/ # 通用基础设施 +│ │ ├── __init__.py +│ │ ├── llm_client.py # OpenAI SDK 兼容 LLM 客户端 +│ │ ├── file_parser.py # 上传文件解析与抽取工具 +│ │ ├── logger.py # 分层日志系统 +│ │ ├── retry.py # 通用重试装饰器/逻辑 +│ │ └── zep_paging.py # Zep 分页读取工具 +│ ├── scripts/ # OASIS 执行脚本 +│ │ ├── run_parallel_simulation.py # Twitter + Reddit 并行模拟入口 +│ │ ├── run_twitter_simulation.py # Twitter 模拟执行脚本 +│ │ ├── run_reddit_simulation.py # Reddit 模拟执行脚本 +│ │ ├── action_logger.py # Agent 行为日志采集脚本 +│ │ └── test_profile_format.py # 画像格式校验脚本 +│ ├── uploads/ # 运行时数据目录(项目/模拟/报告产物) +│ └── logs/ # 后端日志输出目录 +├── static/ +│ └── image/ # README 图片与演示资源 +├── package.json # 根目录脚本(联动前后端) +├── docker-compose.yml # Docker 编排(前端+后端) +├── Dockerfile # Docker 镜像构建定义 +├── .env.example # 环境变量示例 +├── README.md # 中文文档 +├── README-EN.md # 英文文档 +└── LICENSE # 开源许可证 +``` + ## 🚀 快速开始 ### 一、源码部署(推荐) From 5e67ac2fcbb72bd8050233d2aaadc7c4ccf5dabb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:45:08 +0000 Subject: [PATCH 011/373] feat: capture full upstream github state --- .gitignore | 9 +- docs/upstream-all-state.json | 1578 ++++++++++++++++++++++++++++ docs/upstream-all-summary.md | 33 + docs/upstream-open-state.json | 469 ++++++--- docs/upstream-open-summary.md | 49 +- docs/upstream-triage.md | 11 +- scripts/sync_upstream_github.py | 92 +- tests/test_sync_upstream_github.py | 74 ++ 8 files changed, 2126 insertions(+), 189 deletions(-) create mode 100644 docs/upstream-all-state.json create mode 100644 docs/upstream-all-summary.md create mode 100644 tests/test_sync_upstream_github.py diff --git a/.gitignore b/.gitignore index 55d3ef19..b9c36cdb 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,11 @@ backend/logs/ backend/uploads/ # Docker 数据 -data/ \ No newline at end of file +data/ + +# AgentOps session artifacts (auto-added by ao init) +.agents/ + +# Dolt database files (added by bd init) +.dolt/ +*.db diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json new file mode 100644 index 00000000..f019b3fa --- /dev/null +++ b/docs/upstream-all-state.json @@ -0,0 +1,1578 @@ +{ + "repo": "666ghj/MiroFish", + "state": "all", + "captured_at": "2026-03-11T06:44:20.498945+00:00", + "counts": { + "issues": { + "closed": 47, + "open": 32 + }, + "pull_requests": { + "open": 35, + "closed": 12 + } + }, + "issues": [ + { + "number": 121, + "title": "卡在了Exception in handleNewProject: Network Error", + "url": "https://github.com/666ghj/MiroFish/issues/121", + "state": "closed", + "created_at": "2026-03-10T15:46:02Z", + "updated_at": "2026-03-11T02:15:10Z", + "closed_at": "2026-03-11T02:15:10Z", + "labels": [ + "question" + ], + "author": "jackytianjp" + }, + { + "number": 123, + "title": "プリセット業界知識RAGの導入(方式3: ローカルファイル注入)", + "url": "https://github.com/666ghj/MiroFish/issues/123", + "state": "closed", + "created_at": "2026-03-10T21:48:06Z", + "updated_at": "2026-03-10T21:48:44Z", + "closed_at": "2026-03-10T21:48:44Z", + "labels": [], + "author": "minicoohei" + }, + { + "number": 117, + "title": "### Feature Request: English Language Support", + "url": "https://github.com/666ghj/MiroFish/issues/117", + "state": "open", + "created_at": "2026-03-10T08:44:18Z", + "updated_at": "2026-03-10T08:46:24Z", + "closed_at": null, + "labels": [ + "enhancement" + ], + "author": "malpaniga" + }, + { + "number": 110, + "title": "阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用", + "url": "https://github.com/666ghj/MiroFish/issues/110", + "state": "open", + "created_at": "2026-03-10T01:08:29Z", + "updated_at": "2026-03-10T06:40:37Z", + "closed_at": null, + "labels": [ + "LLM API" + ], + "author": "weilb" + }, + { + "number": 64, + "title": "一直卡在上传文件错误:Request failed with status code 500", + "url": "https://github.com/666ghj/MiroFish/issues/64", + "state": "open", + "created_at": "2026-01-31T13:10:06Z", + "updated_at": "2026-03-10T05:40:36Z", + "closed_at": null, + "labels": [], + "author": "G-LJDS2022" + }, + { + "number": 106, + "title": "能否采用除了zep的别的知识图谱", + "url": "https://github.com/666ghj/MiroFish/issues/106", + "state": "open", + "created_at": "2026-03-09T13:55:59Z", + "updated_at": "2026-03-10T02:33:21Z", + "closed_at": null, + "labels": [], + "author": "paipaiio" + }, + { + "number": 109, + "title": "纯小白看到新闻后本机部署,但似乎Zep额度用完后不知道接下来咋办了", + "url": "https://github.com/666ghj/MiroFish/issues/109", + "state": "closed", + "created_at": "2026-03-09T17:33:51Z", + "updated_at": "2026-03-10T02:32:25Z", + "closed_at": "2026-03-10T02:32:24Z", + "labels": [ + "question" + ], + "author": "xingjia10086" + }, + { + "number": 42, + "title": "项目在3/5开始模拟时会消耗大量内存", + "url": "https://github.com/666ghj/MiroFish/issues/42", + "state": "open", + "created_at": "2026-01-21T01:57:50Z", + "updated_at": "2026-03-09T17:28:20Z", + "closed_at": null, + "labels": [], + "author": "s1f102500012" + }, + { + "number": 84, + "title": "报告生成失败,请问有没有办法重新生成?", + "url": "https://github.com/666ghj/MiroFish/issues/84", + "state": "open", + "created_at": "2026-03-08T08:10:41Z", + "updated_at": "2026-03-09T17:26:28Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "luchenwei9266" + }, + { + "number": 107, + "title": "镜像问题", + "url": "https://github.com/666ghj/MiroFish/issues/107", + "state": "open", + "created_at": "2026-03-09T14:44:45Z", + "updated_at": "2026-03-09T14:44:45Z", + "closed_at": null, + "labels": [], + "author": "zhuhw19" + }, + { + "number": 96, + "title": "数字世界agent回复内容异常", + "url": "https://github.com/666ghj/MiroFish/issues/96", + "state": "closed", + "created_at": "2026-03-09T03:04:27Z", + "updated_at": "2026-03-09T11:48:19Z", + "closed_at": "2026-03-09T05:21:15Z", + "labels": [ + "question" + ], + "author": "Lilingjie520" + }, + { + "number": 99, + "title": "Docker镜像没有arm版本", + "url": "https://github.com/666ghj/MiroFish/issues/99", + "state": "open", + "created_at": "2026-03-09T06:52:35Z", + "updated_at": "2026-03-09T06:54:58Z", + "closed_at": null, + "labels": [ + "enhancement" + ], + "author": "linqiu919" + }, + { + "number": 98, + "title": "test", + "url": "https://github.com/666ghj/MiroFish/issues/98", + "state": "closed", + "created_at": "2026-03-09T04:15:56Z", + "updated_at": "2026-03-09T05:20:16Z", + "closed_at": "2026-03-09T05:20:16Z", + "labels": [], + "author": "leon-x-labs" + }, + { + "number": 93, + "title": "`frontend/src/api/index.js`中的`baseURL`不应该硬编码", + "url": "https://github.com/666ghj/MiroFish/issues/93", + "state": "open", + "created_at": "2026-03-08T16:44:24Z", + "updated_at": "2026-03-09T01:53:47Z", + "closed_at": null, + "labels": [ + "enhancement" + ], + "author": "HexStan" + }, + { + "number": 95, + "title": "为什么回答一模一样?", + "url": "https://github.com/666ghj/MiroFish/issues/95", + "state": "closed", + "created_at": "2026-03-09T01:02:45Z", + "updated_at": "2026-03-09T01:11:44Z", + "closed_at": "2026-03-09T01:11:44Z", + "labels": [ + "question" + ], + "author": "YHLpuyu" + }, + { + "number": 94, + "title": "测试issue", + "url": "https://github.com/666ghj/MiroFish/issues/94", + "state": "closed", + "created_at": "2026-03-09T00:51:55Z", + "updated_at": "2026-03-09T00:52:24Z", + "closed_at": "2026-03-09T00:52:24Z", + "labels": [], + "author": "breadbot86" + }, + { + "number": 92, + "title": "Upgrade GitHub Actions", + "url": "https://github.com/666ghj/MiroFish/issues/92", + "state": "open", + "created_at": "2026-03-08T15:26:04Z", + "updated_at": "2026-03-08T15:28:09Z", + "closed_at": null, + "labels": [ + "enhancement" + ], + "author": "leon-x-labs" + }, + { + "number": 90, + "title": "预测的很好!!!", + "url": "https://github.com/666ghj/MiroFish/issues/90", + "state": "closed", + "created_at": "2026-03-08T12:10:00Z", + "updated_at": "2026-03-08T12:27:39Z", + "closed_at": "2026-03-08T12:27:39Z", + "labels": [], + "author": "betatoo" + }, + { + "number": 88, + "title": "问卷调查1+1=?回答是认真的吗", + "url": "https://github.com/666ghj/MiroFish/issues/88", + "state": "closed", + "created_at": "2026-03-08T12:04:11Z", + "updated_at": "2026-03-08T12:07:19Z", + "closed_at": "2026-03-08T12:07:19Z", + "labels": [ + "Q&A" + ], + "author": "huahuayu" + }, + { + "number": 80, + "title": "Lácteos CCC", + "url": "https://github.com/666ghj/MiroFish/issues/80", + "state": "closed", + "created_at": "2026-03-07T20:24:42Z", + "updated_at": "2026-03-08T04:00:16Z", + "closed_at": "2026-03-08T04:00:16Z", + "labels": [], + "author": "cristian9777" + }, + { + "number": 83, + "title": "Demo test-report test is not complete.", + "url": "https://github.com/666ghj/MiroFish/issues/83", + "state": "closed", + "created_at": "2026-03-08T03:34:29Z", + "updated_at": "2026-03-08T03:59:46Z", + "closed_at": "2026-03-08T03:59:46Z", + "labels": [], + "author": "yizhi1523-art" + }, + { + "number": 78, + "title": "有mirofish和前作bettafish的场景/性能对比吗", + "url": "https://github.com/666ghj/MiroFish/issues/78", + "state": "closed", + "created_at": "2026-03-07T03:08:43Z", + "updated_at": "2026-03-07T03:16:07Z", + "closed_at": "2026-03-07T03:16:07Z", + "labels": [ + "question" + ], + "author": "flappy5812" + }, + { + "number": 56, + "title": "Zep 本地化实现方案交流专贴", + "url": "https://github.com/666ghj/MiroFish/issues/56", + "state": "open", + "created_at": "2026-01-23T07:24:57Z", + "updated_at": "2026-03-06T01:40:22Z", + "closed_at": null, + "labels": [], + "author": "666ghj" + }, + { + "number": 48, + "title": "在按照格式填写api等数据并写入环境变量后仍然无法进行第一步", + "url": "https://github.com/666ghj/MiroFish/issues/48", + "state": "closed", + "created_at": "2026-01-21T16:01:08Z", + "updated_at": "2026-03-05T16:28:05Z", + "closed_at": "2026-03-05T16:28:05Z", + "labels": [], + "author": "qi-1021" + }, + { + "number": 77, + "title": "国内部署 MiroFish,Zep API Key 认证持续失败", + "url": "https://github.com/666ghj/MiroFish/issues/77", + "state": "closed", + "created_at": "2026-02-28T14:45:15Z", + "updated_at": "2026-03-05T05:25:02Z", + "closed_at": "2026-03-05T05:25:02Z", + "labels": [ + "LLM API" + ], + "author": "bolin0759" + }, + { + "number": 68, + "title": "尝试进行首次模拟,等待了1夜还是在3/5的阶段", + "url": "https://github.com/666ghj/MiroFish/issues/68", + "state": "open", + "created_at": "2026-02-10T01:19:08Z", + "updated_at": "2026-03-01T08:29:56Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "GarretRen" + }, + { + "number": 75, + "title": "Zep 的免费限速会让进度卡99%", + "url": "https://github.com/666ghj/MiroFish/issues/75", + "state": "open", + "created_at": "2026-02-26T08:35:41Z", + "updated_at": "2026-02-28T08:13:33Z", + "closed_at": null, + "labels": [], + "author": "fengkuangyibo" + }, + { + "number": 63, + "title": "卡在Debugger PIN: 137-310-617,无法往下走了,是为甚麽", + "url": "https://github.com/666ghj/MiroFish/issues/63", + "state": "closed", + "created_at": "2026-01-28T11:12:29Z", + "updated_at": "2026-02-28T08:12:13Z", + "closed_at": "2026-02-28T08:12:13Z", + "labels": [], + "author": "lxb20251022" + }, + { + "number": 76, + "title": "知识图谱构建提供接入 ragflow api 的功能", + "url": "https://github.com/666ghj/MiroFish/issues/76", + "state": "open", + "created_at": "2026-02-27T12:02:39Z", + "updated_at": "2026-02-28T08:02:11Z", + "closed_at": null, + "labels": [ + "Memory Layer" + ], + "author": "Hitomogami" + }, + { + "number": 71, + "title": "输入文件选择多个时,前端没有正确预留空间", + "url": "https://github.com/666ghj/MiroFish/issues/71", + "state": "closed", + "created_at": "2026-02-14T16:16:31Z", + "updated_at": "2026-02-22T15:41:08Z", + "closed_at": "2026-02-22T15:41:08Z", + "labels": [], + "author": "MoeclubM" + }, + { + "number": 59, + "title": "上传文件时出现Exception in handleNewProject: Network Error报错", + "url": "https://github.com/666ghj/MiroFish/issues/59", + "state": "closed", + "created_at": "2026-01-24T14:25:43Z", + "updated_at": "2026-02-22T09:42:07Z", + "closed_at": "2026-02-22T09:42:07Z", + "labels": [], + "author": "HenryZhou2008" + }, + { + "number": 9, + "title": "可以设置中断重新加载吗", + "url": "https://github.com/666ghj/MiroFish/issues/9", + "state": "open", + "created_at": "2025-12-28T13:16:54Z", + "updated_at": "2026-02-21T09:55:20Z", + "closed_at": null, + "labels": [], + "author": "LMG-arch" + }, + { + "number": 67, + "title": "生成内容过于离谱", + "url": "https://github.com/666ghj/MiroFish/issues/67", + "state": "closed", + "created_at": "2026-02-09T07:08:21Z", + "updated_at": "2026-02-10T08:43:01Z", + "closed_at": "2026-02-10T08:43:01Z", + "labels": [], + "author": "Charlo-O" + }, + { + "number": 69, + "title": "模型对接", + "url": "https://github.com/666ghj/MiroFish/issues/69", + "state": "open", + "created_at": "2026-02-10T07:53:43Z", + "updated_at": "2026-02-10T07:56:20Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "wjh-w" + }, + { + "number": 37, + "title": "模拟环境未运行或已关闭,无法执行Interview: sim_66f01bcf8013。模拟环境可能已关闭,请确保OASIS环境正在运行。", + "url": "https://github.com/666ghj/MiroFish/issues/37", + "state": "open", + "created_at": "2026-01-20T09:10:49Z", + "updated_at": "2026-02-09T04:54:14Z", + "closed_at": null, + "labels": [], + "author": "Ezj-Amon" + }, + { + "number": 66, + "title": "使用docker 运行之后 启动引擎一直处于灰色无法点击状态", + "url": "https://github.com/666ghj/MiroFish/issues/66", + "state": "closed", + "created_at": "2026-02-03T02:35:42Z", + "updated_at": "2026-02-03T02:41:27Z", + "closed_at": "2026-02-03T02:41:27Z", + "labels": [], + "author": "wjh-w" + }, + { + "number": 65, + "title": "docker 运行之后 页面一直 启动引擎一直处于无法点击的状态", + "url": "https://github.com/666ghj/MiroFish/issues/65", + "state": "closed", + "created_at": "2026-02-03T02:34:31Z", + "updated_at": "2026-02-03T02:34:54Z", + "closed_at": "2026-02-03T02:34:54Z", + "labels": [], + "author": "wjh-w" + }, + { + "number": 60, + "title": "Zep 免费计划 429 限流导致图谱构建失败(请求过密)", + "url": "https://github.com/666ghj/MiroFish/issues/60", + "state": "open", + "created_at": "2026-01-24T16:03:41Z", + "updated_at": "2026-01-28T08:36:57Z", + "closed_at": null, + "labels": [], + "author": "Jonah-Wu23" + }, + { + "number": 61, + "title": "能否将修改api的功能在前端也实现", + "url": "https://github.com/666ghj/MiroFish/issues/61", + "state": "open", + "created_at": "2026-01-27T13:37:15Z", + "updated_at": "2026-01-28T08:35:08Z", + "closed_at": null, + "labels": [], + "author": "skoa323" + }, + { + "number": 62, + "title": "很好的创意,专门注册来提提问题和建议啦", + "url": "https://github.com/666ghj/MiroFish/issues/62", + "state": "open", + "created_at": "2026-01-28T01:39:38Z", + "updated_at": "2026-01-28T08:34:36Z", + "closed_at": null, + "labels": [], + "author": "piaopiaomiaomiao" + }, + { + "number": 58, + "title": "使用ollama加载的本地大模型启动引擎时经常会遇到超时问题", + "url": "https://github.com/666ghj/MiroFish/issues/58", + "state": "open", + "created_at": "2026-01-24T10:47:13Z", + "updated_at": "2026-01-24T16:18:14Z", + "closed_at": null, + "labels": [], + "author": "ThomasWang071001" + }, + { + "number": 57, + "title": "Exception in handleNewProject: Network Error", + "url": "https://github.com/666ghj/MiroFish/issues/57", + "state": "closed", + "created_at": "2026-01-24T03:21:30Z", + "updated_at": "2026-01-24T03:28:54Z", + "closed_at": "2026-01-24T03:28:54Z", + "labels": [], + "author": "ham0nd" + }, + { + "number": 46, + "title": "npm安装依赖和配置提示project.license` as a TOML table is deprecated", + "url": "https://github.com/666ghj/MiroFish/issues/46", + "state": "open", + "created_at": "2026-01-21T12:26:05Z", + "updated_at": "2026-01-23T10:34:52Z", + "closed_at": null, + "labels": [], + "author": "Vamco2022" + }, + { + "number": 40, + "title": "更换Zep密钥后后端会仍然使用旧Key", + "url": "https://github.com/666ghj/MiroFish/issues/40", + "state": "closed", + "created_at": "2026-01-20T15:32:59Z", + "updated_at": "2026-01-23T08:20:40Z", + "closed_at": "2026-01-23T08:20:40Z", + "labels": [], + "author": "s1f102500012" + }, + { + "number": 50, + "title": "实体重复不一致问题", + "url": "https://github.com/666ghj/MiroFish/issues/50", + "state": "closed", + "created_at": "2026-01-22T13:18:17Z", + "updated_at": "2026-01-23T06:32:15Z", + "closed_at": "2026-01-23T06:32:15Z", + "labels": [], + "author": "ngyygm" + }, + { + "number": 51, + "title": "中英文语言混乱问题", + "url": "https://github.com/666ghj/MiroFish/issues/51", + "state": "closed", + "created_at": "2026-01-22T13:20:20Z", + "updated_at": "2026-01-23T06:31:25Z", + "closed_at": "2026-01-23T06:31:25Z", + "labels": [], + "author": "ngyygm" + }, + { + "number": 55, + "title": "做了一个基于本地neo4j的版本", + "url": "https://github.com/666ghj/MiroFish/issues/55", + "state": "open", + "created_at": "2026-01-23T03:08:03Z", + "updated_at": "2026-01-23T06:27:04Z", + "closed_at": null, + "labels": [], + "author": "xumengke2025-sys" + }, + { + "number": 53, + "title": "docker尝试时需要下载4.7个G ~", + "url": "https://github.com/666ghj/MiroFish/issues/53", + "state": "closed", + "created_at": "2026-01-22T14:08:38Z", + "updated_at": "2026-01-23T06:25:40Z", + "closed_at": "2026-01-23T06:25:40Z", + "labels": [], + "author": "lowpair" + }, + { + "number": 54, + "title": "太喜欢你这个项目了!给了我巨大的帮助!", + "url": "https://github.com/666ghj/MiroFish/issues/54", + "state": "open", + "created_at": "2026-01-23T02:39:53Z", + "updated_at": "2026-01-23T02:39:53Z", + "closed_at": null, + "labels": [], + "author": "zb2947244682" + }, + { + "number": 52, + "title": "API最大长度超过导致程序奔溃", + "url": "https://github.com/666ghj/MiroFish/issues/52", + "state": "open", + "created_at": "2026-01-22T13:25:33Z", + "updated_at": "2026-01-22T13:25:33Z", + "closed_at": null, + "labels": [], + "author": "ngyygm" + }, + { + "number": 5, + "title": "是否能提供Docker部署方式", + "url": "https://github.com/666ghj/MiroFish/issues/5", + "state": "closed", + "created_at": "2025-12-23T04:50:17Z", + "updated_at": "2026-01-22T10:31:05Z", + "closed_at": "2026-01-22T10:31:05Z", + "labels": [], + "author": "ghost" + }, + { + "number": 22, + "title": "能否给打包个现成镜像", + "url": "https://github.com/666ghj/MiroFish/issues/22", + "state": "closed", + "created_at": "2026-01-14T09:35:27Z", + "updated_at": "2026-01-22T10:30:47Z", + "closed_at": "2026-01-22T10:30:47Z", + "labels": [], + "author": "busyJoker512" + }, + { + "number": 47, + "title": "运算过程中,图谱加载失败: Request failed with status code 500", + "url": "https://github.com/666ghj/MiroFish/issues/47", + "state": "closed", + "created_at": "2026-01-21T12:38:56Z", + "updated_at": "2026-01-22T10:30:23Z", + "closed_at": "2026-01-22T10:30:23Z", + "labels": [], + "author": "xumengke2025-sys" + }, + { + "number": 41, + "title": "Zep 可以使用 Neo4j来替代嘛", + "url": "https://github.com/666ghj/MiroFish/issues/41", + "state": "closed", + "created_at": "2026-01-21T01:08:01Z", + "updated_at": "2026-01-22T10:29:48Z", + "closed_at": "2026-01-22T10:29:48Z", + "labels": [], + "author": "dbplayer-git" + }, + { + "number": 39, + "title": "上传文本时出现Exception in handleNewProject: Network Error的报错", + "url": "https://github.com/666ghj/MiroFish/issues/39", + "state": "closed", + "created_at": "2026-01-20T11:05:39Z", + "updated_at": "2026-01-22T10:28:56Z", + "closed_at": "2026-01-22T10:28:58Z", + "labels": [], + "author": "s1f102500012" + }, + { + "number": 24, + "title": "ERROR: 报告生成失败: 'NoneType' object is not subscriptable", + "url": "https://github.com/666ghj/MiroFish/issues/24", + "state": "open", + "created_at": "2026-01-14T15:53:08Z", + "updated_at": "2026-01-21T13:28:41Z", + "closed_at": null, + "labels": [], + "author": "Joe-rq" + }, + { + "number": 45, + "title": "与世界中任意个体对话功能和发送调查问卷到世界中 两个功能报错 IPC 响应 failed", + "url": "https://github.com/666ghj/MiroFish/issues/45", + "state": "open", + "created_at": "2026-01-21T06:46:41Z", + "updated_at": "2026-01-21T07:11:18Z", + "closed_at": null, + "labels": [], + "author": "LucasXu666666" + }, + { + "number": 43, + "title": "在使用时调用IPC超时", + "url": "https://github.com/666ghj/MiroFish/issues/43", + "state": "open", + "created_at": "2026-01-21T02:23:35Z", + "updated_at": "2026-01-21T07:10:12Z", + "closed_at": null, + "labels": [], + "author": "dbplayer-git" + }, + { + "number": 23, + "title": "有没有开源替换zep,消耗太快了", + "url": "https://github.com/666ghj/MiroFish/issues/23", + "state": "closed", + "created_at": "2026-01-14T09:50:25Z", + "updated_at": "2026-01-20T08:05:29Z", + "closed_at": "2026-01-20T08:05:29Z", + "labels": [], + "author": "ngstorm" + }, + { + "number": 4, + "title": "So powerful!", + "url": "https://github.com/666ghj/MiroFish/issues/4", + "state": "closed", + "created_at": "2025-12-23T02:17:13Z", + "updated_at": "2026-01-20T08:05:04Z", + "closed_at": "2026-01-20T08:05:04Z", + "labels": [], + "author": "ichont" + }, + { + "number": 3, + "title": "很酷的项目", + "url": "https://github.com/666ghj/MiroFish/issues/3", + "state": "closed", + "created_at": "2025-12-23T02:04:12Z", + "updated_at": "2026-01-20T08:04:59Z", + "closed_at": "2026-01-20T08:04:59Z", + "labels": [], + "author": "sairson" + }, + { + "number": 8, + "title": "请问用哪个模型效果最稳定", + "url": "https://github.com/666ghj/MiroFish/issues/8", + "state": "closed", + "created_at": "2025-12-27T03:28:24Z", + "updated_at": "2026-01-20T08:04:52Z", + "closed_at": "2026-01-20T08:04:52Z", + "labels": [], + "author": "zellelin2023-create" + }, + { + "number": 26, + "title": "开始模拟没响应,F12查看接口报进程错误", + "url": "https://github.com/666ghj/MiroFish/issues/26", + "state": "closed", + "created_at": "2026-01-15T03:54:47Z", + "updated_at": "2026-01-20T08:04:13Z", + "closed_at": "2026-01-20T08:04:13Z", + "labels": [], + "author": "ivwpuw" + }, + { + "number": 27, + "title": "Zep的免费计划总是报错:Rate Limit Exceeded", + "url": "https://github.com/666ghj/MiroFish/issues/27", + "state": "closed", + "created_at": "2026-01-15T09:02:46Z", + "updated_at": "2026-01-20T08:03:36Z", + "closed_at": "2026-01-20T08:03:36Z", + "labels": [], + "author": "devTech-zhang" + }, + { + "number": 29, + "title": "怎么样停用加速 LLM 配置?不然会一直报gpt-4o-mini模型相关错", + "url": "https://github.com/666ghj/MiroFish/issues/29", + "state": "closed", + "created_at": "2026-01-15T10:29:35Z", + "updated_at": "2026-01-20T08:03:13Z", + "closed_at": "2026-01-20T08:03:13Z", + "labels": [], + "author": "ivwpuw" + }, + { + "number": 28, + "title": "建议:增加,网络搜索的选项", + "url": "https://github.com/666ghj/MiroFish/issues/28", + "state": "closed", + "created_at": "2026-01-15T09:35:55Z", + "updated_at": "2026-01-20T08:02:04Z", + "closed_at": "2026-01-20T08:02:04Z", + "labels": [], + "author": "ferocknew" + }, + { + "number": 30, + "title": "报告生成这一步失败了,刷新网页无任何重试效果", + "url": "https://github.com/666ghj/MiroFish/issues/30", + "state": "closed", + "created_at": "2026-01-16T01:32:16Z", + "updated_at": "2026-01-20T07:59:15Z", + "closed_at": "2026-01-20T07:59:15Z", + "labels": [], + "author": "stone100010" + }, + { + "number": 31, + "title": "请问如何减少第三步开始模拟的并发数量?RPM超出限制报500错误。", + "url": "https://github.com/666ghj/MiroFish/issues/31", + "state": "closed", + "created_at": "2026-01-17T00:34:37Z", + "updated_at": "2026-01-20T07:58:19Z", + "closed_at": "2026-01-20T07:58:19Z", + "labels": [], + "author": "Neal3923" + }, + { + "number": 34, + "title": "建议新增“热门榜单”,根据热门做选题。", + "url": "https://github.com/666ghj/MiroFish/issues/34", + "state": "closed", + "created_at": "2026-01-19T02:12:55Z", + "updated_at": "2026-01-20T07:54:41Z", + "closed_at": "2026-01-20T07:54:41Z", + "labels": [], + "author": "lpf479" + }, + { + "number": 35, + "title": "Zep建议替换为本地构建", + "url": "https://github.com/666ghj/MiroFish/issues/35", + "state": "closed", + "created_at": "2026-01-19T09:01:32Z", + "updated_at": "2026-01-20T07:53:14Z", + "closed_at": "2026-01-20T07:53:14Z", + "labels": [], + "author": "jjy1000" + }, + { + "number": 36, + "title": "uv环境建议加上清华源", + "url": "https://github.com/666ghj/MiroFish/issues/36", + "state": "closed", + "created_at": "2026-01-20T07:24:40Z", + "updated_at": "2026-01-20T07:49:59Z", + "closed_at": "2026-01-20T07:49:59Z", + "labels": [], + "author": "Ezj-Amon" + }, + { + "number": 32, + "title": "无法识别第三方兼容的openai接口,必须在.env添加LLM_PROVIDER=openai后才能识别", + "url": "https://github.com/666ghj/MiroFish/issues/32", + "state": "closed", + "created_at": "2026-01-17T00:38:27Z", + "updated_at": "2026-01-20T07:48:26Z", + "closed_at": "2026-01-20T07:48:26Z", + "labels": [], + "author": "Neal3923" + }, + { + "number": 19, + "title": "建议初次使用不用太大的pdf", + "url": "https://github.com/666ghj/MiroFish/issues/19", + "state": "open", + "created_at": "2026-01-14T02:45:19Z", + "updated_at": "2026-01-15T05:57:37Z", + "closed_at": null, + "labels": [], + "author": "paperplane123" + }, + { + "number": 21, + "title": "部署在群辉服务器上,docker里启动了服务,然后用过反向代理可以访问前端了,如果已经开始模拟了,刷新网页或者关掉再打开会发生什么", + "url": "https://github.com/666ghj/MiroFish/issues/21", + "state": "open", + "created_at": "2026-01-14T08:33:53Z", + "updated_at": "2026-01-14T08:33:53Z", + "closed_at": null, + "labels": [], + "author": "usernametooshort" + }, + { + "number": 20, + "title": "中国银发经济", + "url": "https://github.com/666ghj/MiroFish/issues/20", + "state": "closed", + "created_at": "2026-01-14T08:28:10Z", + "updated_at": "2026-01-14T08:28:37Z", + "closed_at": "2026-01-14T08:28:37Z", + "labels": [], + "author": "XenaQi" + }, + { + "number": 17, + "title": "多次仿真 + 元报告共识,提升预测结果的可信度", + "url": "https://github.com/666ghj/MiroFish/issues/17", + "state": "open", + "created_at": "2026-01-06T09:07:51Z", + "updated_at": "2026-01-06T09:07:51Z", + "closed_at": null, + "labels": [], + "author": "tt-a1i" + }, + { + "number": 16, + "title": "Ignore (created by mistake)", + "url": "https://github.com/666ghj/MiroFish/issues/16", + "state": "closed", + "created_at": "2026-01-06T08:51:20Z", + "updated_at": "2026-01-06T08:55:04Z", + "closed_at": "2026-01-06T08:53:01Z", + "labels": [], + "author": "tt-a1i" + }, + { + "number": 14, + "title": "Frontend doesn't show error when simulation fails", + "url": "https://github.com/666ghj/MiroFish/issues/14", + "state": "open", + "created_at": "2026-01-05T11:43:44Z", + "updated_at": "2026-01-06T06:15:22Z", + "closed_at": null, + "labels": [], + "author": "tt-a1i" + }, + { + "number": 11, + "title": "请问前后端服务起来后 为什么一段时间不用后 自动停止服务", + "url": "https://github.com/666ghj/MiroFish/issues/11", + "state": "closed", + "created_at": "2025-12-30T01:33:19Z", + "updated_at": "2025-12-30T07:23:39Z", + "closed_at": "2025-12-30T07:23:39Z", + "labels": [], + "author": "zkkkkkk72" + } + ], + "pull_requests": [ + { + "number": 105, + "title": "fix: security improvements and error handling fixes", + "url": "https://github.com/666ghj/MiroFish/pull/105", + "state": "open", + "created_at": "2026-03-09T11:57:58Z", + "updated_at": "2026-03-11T05:48:53Z", + "closed_at": null, + "merged_at": null, + "head": "fix/security-improvements", + "base": "main", + "draft": false, + "author": "hobostay" + }, + { + "number": 132, + "title": "docs:add simple system architecture part for README-EN.md & README.md", + "url": "https://github.com/666ghj/MiroFish/pull/132", + "state": "open", + "created_at": "2026-03-11T05:45:53Z", + "updated_at": "2026-03-11T05:47:00Z", + "closed_at": null, + "merged_at": null, + "head": "docs/add-sys-architecture-part", + "base": "main", + "draft": false, + "author": "Noblegasesgoo" + }, + { + "number": 131, + "title": "feat(graph_builder): add retry mechanism for Zep Cloud connection failures", + "url": "https://github.com/666ghj/MiroFish/pull/131", + "state": "open", + "created_at": "2026-03-11T05:42:07Z", + "updated_at": "2026-03-11T05:43:10Z", + "closed_at": null, + "merged_at": null, + "head": "feat/zep-retry-mechanism", + "base": "main", + "draft": false, + "author": "EuanTop" + }, + { + "number": 130, + "title": "docs: 添加贡献指南文档", + "url": "https://github.com/666ghj/MiroFish/pull/130", + "state": "open", + "created_at": "2026-03-11T04:24:56Z", + "updated_at": "2026-03-11T04:26:00Z", + "closed_at": null, + "merged_at": null, + "head": "docs/add-pr-guide", + "base": "main", + "draft": false, + "author": "M-Tlinqinming" + }, + { + "number": 120, + "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", + "url": "https://github.com/666ghj/MiroFish/pull/120", + "state": "open", + "created_at": "2026-03-10T15:41:04Z", + "updated_at": "2026-03-11T03:54:11Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "28764116" + }, + { + "number": 129, + "title": "fix(report_agent): handle API token overflow crash with context lengt…", + "url": "https://github.com/666ghj/MiroFish/pull/129", + "state": "open", + "created_at": "2026-03-11T02:55:33Z", + "updated_at": "2026-03-11T02:56:38Z", + "closed_at": null, + "merged_at": null, + "head": "fix/fix-priority-issues-mNNjT", + "base": "main", + "draft": false, + "author": "ai-x-builder" + }, + { + "number": 127, + "title": "Fix potential crash in LLMClient when content is None", + "url": "https://github.com/666ghj/MiroFish/pull/127", + "state": "open", + "created_at": "2026-03-10T22:43:33Z", + "updated_at": "2026-03-10T22:44:42Z", + "closed_at": null, + "merged_at": null, + "head": "fix/llm-client-none-content", + "base": "main", + "draft": false, + "author": "sjhddh" + }, + { + "number": 126, + "title": "feat: Add custom exceptions and enhanced config validation", + "url": "https://github.com/666ghj/MiroFish/pull/126", + "state": "open", + "created_at": "2026-03-10T22:12:22Z", + "updated_at": "2026-03-10T22:13:37Z", + "closed_at": null, + "merged_at": null, + "head": "feature/custom-exceptions-and-config-validation", + "base": "main", + "draft": false, + "author": "ZaviQ7" + }, + { + "number": 125, + "title": "fix: improve new-project network error diagnostics", + "url": "https://github.com/666ghj/MiroFish/pull/125", + "state": "open", + "created_at": "2026-03-10T21:50:43Z", + "updated_at": "2026-03-10T21:51:51Z", + "closed_at": null, + "merged_at": null, + "head": "fix/issue-121", + "base": "main", + "draft": false, + "author": "SergioChan" + }, + { + "number": 124, + "title": "fix: robust JSON extraction for mixed LLM responses", + "url": "https://github.com/666ghj/MiroFish/pull/124", + "state": "open", + "created_at": "2026-03-10T21:50:31Z", + "updated_at": "2026-03-10T21:51:46Z", + "closed_at": null, + "merged_at": null, + "head": "fix/issue-64", + "base": "main", + "draft": false, + "author": "SergioChan" + }, + { + "number": 122, + "title": "fix(llm_client): remove response_format json_object for local LLM compatibility", + "url": "https://github.com/666ghj/MiroFish/pull/122", + "state": "open", + "created_at": "2026-03-10T18:20:49Z", + "updated_at": "2026-03-10T18:33:48Z", + "closed_at": null, + "merged_at": null, + "head": "fix/lm-studio-json-object-compat", + "base": "main", + "draft": false, + "author": "ImL1s" + }, + { + "number": 119, + "title": "feat: add an option to switch to english language", + "url": "https://github.com/666ghj/MiroFish/pull/119", + "state": "open", + "created_at": "2026-03-10T15:05:40Z", + "updated_at": "2026-03-10T18:14:33Z", + "closed_at": null, + "merged_at": null, + "head": "language-option", + "base": "main", + "draft": false, + "author": "Pratiyankkumar" + }, + { + "number": 89, + "title": "feat(graph): update graph rendering with Sigma.js and integrate new d…", + "url": "https://github.com/666ghj/MiroFish/pull/89", + "state": "closed", + "created_at": "2026-03-08T12:09:13Z", + "updated_at": "2026-03-10T09:49:08Z", + "closed_at": "2026-03-10T09:49:08Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "zzfe-501" + }, + { + "number": 118, + "title": "feat(ragflow): add RAGflow as alternative graph backend with full pip…", + "url": "https://github.com/666ghj/MiroFish/pull/118", + "state": "open", + "created_at": "2026-03-10T09:29:33Z", + "updated_at": "2026-03-10T09:30:44Z", + "closed_at": null, + "merged_at": null, + "head": "fix/ragflow-pattern-compliance", + "base": "main", + "draft": false, + "author": "pratyush618" + }, + { + "number": 116, + "title": "Upgrade GitHub Actions", + "url": "https://github.com/666ghj/MiroFish/pull/116", + "state": "open", + "created_at": "2026-03-10T07:30:38Z", + "updated_at": "2026-03-10T07:30:42Z", + "closed_at": null, + "merged_at": null, + "head": "chore/upgrade-actions", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 115, + "title": "Use SPDX license string", + "url": "https://github.com/666ghj/MiroFish/pull/115", + "state": "open", + "created_at": "2026-03-10T07:28:37Z", + "updated_at": "2026-03-10T07:28:41Z", + "closed_at": null, + "merged_at": null, + "head": "fix/pyproject-license", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 114, + "title": "Fix API base URL fallback", + "url": "https://github.com/666ghj/MiroFish/pull/114", + "state": "open", + "created_at": "2026-03-10T07:21:29Z", + "updated_at": "2026-03-10T07:21:49Z", + "closed_at": null, + "merged_at": null, + "head": "fix/api-baseurl-default", + "base": "main", + "draft": false, + "author": "ailuntz" + }, + { + "number": 113, + "title": "docs(readme): add Japanese README", + "url": "https://github.com/666ghj/MiroFish/pull/113", + "state": "open", + "created_at": "2026-03-10T06:43:16Z", + "updated_at": "2026-03-10T06:44:34Z", + "closed_at": null, + "merged_at": null, + "head": "add-ja-doc", + "base": "main", + "draft": false, + "author": "eltociear" + }, + { + "number": 112, + "title": "Korean README.md added", + "url": "https://github.com/666ghj/MiroFish/pull/112", + "state": "open", + "created_at": "2026-03-10T05:25:01Z", + "updated_at": "2026-03-10T05:25:55Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "waitle" + }, + { + "number": 72, + "title": "清理模型返回的markdown标记", + "url": "https://github.com/666ghj/MiroFish/pull/72", + "state": "open", + "created_at": "2026-02-15T05:27:05Z", + "updated_at": "2026-03-10T02:58:45Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "MoeclubM" + }, + { + "number": 108, + "title": "feat(installer): add Windows installer build scripts", + "url": "https://github.com/666ghj/MiroFish/pull/108", + "state": "open", + "created_at": "2026-03-09T17:14:55Z", + "updated_at": "2026-03-09T17:16:21Z", + "closed_at": null, + "merged_at": null, + "head": "feat/windows-installer", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 104, + "title": "fix: make vite proxy target configurable via environment variable", + "url": "https://github.com/666ghj/MiroFish/pull/104", + "state": "open", + "created_at": "2026-03-09T09:05:37Z", + "updated_at": "2026-03-09T09:06:54Z", + "closed_at": null, + "merged_at": null, + "head": "fix/remove-hardcoded-api-url", + "base": "main", + "draft": false, + "author": "nil957" + }, + { + "number": 103, + "title": "ci: upgrade GitHub Actions and add ARM64 Docker support", + "url": "https://github.com/666ghj/MiroFish/pull/103", + "state": "open", + "created_at": "2026-03-09T09:03:45Z", + "updated_at": "2026-03-09T09:04:59Z", + "closed_at": null, + "merged_at": null, + "head": "fix/upgrade-actions-and-arm-support", + "base": "main", + "draft": false, + "author": "nil957" + }, + { + "number": 91, + "title": "求个能稳定加速gpt和gemini网页和api的vpn代理,我现在用的api好不稳 ", + "url": "https://github.com/666ghj/MiroFish/pull/91", + "state": "closed", + "created_at": "2026-03-08T15:25:24Z", + "updated_at": "2026-03-09T08:55:26Z", + "closed_at": "2026-03-09T08:55:26Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "leon-x-labs" + }, + { + "number": 102, + "title": "fix(ci): add multi-platform Docker build for ARM64 support", + "url": "https://github.com/666ghj/MiroFish/pull/102", + "state": "open", + "created_at": "2026-03-09T08:25:27Z", + "updated_at": "2026-03-09T08:26:30Z", + "closed_at": null, + "merged_at": null, + "head": "fix/docker-multiplatform", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 101, + "title": "feat(utils): add json_utils module for robust LLM JSON parsing", + "url": "https://github.com/666ghj/MiroFish/pull/101", + "state": "open", + "created_at": "2026-03-09T08:23:07Z", + "updated_at": "2026-03-09T08:24:20Z", + "closed_at": null, + "merged_at": null, + "head": "feat/json-utils-helper", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 100, + "title": "fix(frontend): use relative baseURL in production, avoid hardcoded localhost", + "url": "https://github.com/666ghj/MiroFish/pull/100", + "state": "open", + "created_at": "2026-03-09T08:19:23Z", + "updated_at": "2026-03-09T08:20:38Z", + "closed_at": null, + "merged_at": null, + "head": "fix/frontend-baseurl", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 97, + "title": "Feature/local graphrag", + "url": "https://github.com/666ghj/MiroFish/pull/97", + "state": "closed", + "created_at": "2026-03-09T03:06:31Z", + "updated_at": "2026-03-09T03:10:49Z", + "closed_at": "2026-03-09T03:08:50Z", + "merged_at": null, + "head": "feature/local-graphrag", + "base": "main", + "draft": false, + "author": "Jerry050512" + }, + { + "number": 87, + "title": "Upgrade GitHub Actions to latest versions", + "url": "https://github.com/666ghj/MiroFish/pull/87", + "state": "open", + "created_at": "2026-03-08T09:09:13Z", + "updated_at": "2026-03-08T09:09:19Z", + "closed_at": null, + "merged_at": null, + "head": "upgrade-github-actions-node24-general", + "base": "main", + "draft": false, + "author": "salmanmkc" + }, + { + "number": 86, + "title": "Upgrade GitHub Actions for Node 24 compatibility", + "url": "https://github.com/666ghj/MiroFish/pull/86", + "state": "open", + "created_at": "2026-03-08T09:09:10Z", + "updated_at": "2026-03-08T09:09:14Z", + "closed_at": null, + "merged_at": null, + "head": "upgrade-github-actions-node24", + "base": "main", + "draft": false, + "author": "salmanmkc" + }, + { + "number": 82, + "title": "[Security] Fix CRITICAL vulnerability: CVE-2025-64712", + "url": "https://github.com/666ghj/MiroFish/pull/82", + "state": "open", + "created_at": "2026-03-08T02:45:42Z", + "updated_at": "2026-03-08T02:45:46Z", + "closed_at": null, + "merged_at": null, + "head": "fix-cve-2025-64712-unstructured", + "base": "main", + "draft": false, + "author": "orbisai0security" + }, + { + "number": 81, + "title": "feat: add configurable API timeout for slow local LLMs", + "url": "https://github.com/666ghj/MiroFish/pull/81", + "state": "open", + "created_at": "2026-03-08T02:34:41Z", + "updated_at": "2026-03-08T02:35:36Z", + "closed_at": null, + "merged_at": null, + "head": "fix/issue-58-configurable-timeout", + "base": "main", + "draft": false, + "author": "JasonOA888" + }, + { + "number": 13, + "title": "feat: v0.2.0-beta - History UI, resume/cache, native tool calls (开发预览版)", + "url": "https://github.com/666ghj/MiroFish/pull/13", + "state": "closed", + "created_at": "2026-01-03T08:33:03Z", + "updated_at": "2026-03-06T07:48:07Z", + "closed_at": "2026-03-06T07:48:07Z", + "merged_at": null, + "head": "feat/local-resume-history-smoke", + "base": "main", + "draft": false, + "author": "martin0359" + }, + { + "number": 74, + "title": "fix: replace 4 bare excepts with except Exception", + "url": "https://github.com/666ghj/MiroFish/pull/74", + "state": "open", + "created_at": "2026-02-25T03:01:43Z", + "updated_at": "2026-02-25T09:20:00Z", + "closed_at": null, + "merged_at": null, + "head": "fix/bare-excepts", + "base": "main", + "draft": false, + "author": "haosenwang1018" + }, + { + "number": 73, + "title": "fix: Handle string entities/edges in _validate_and_process", + "url": "https://github.com/666ghj/MiroFish/pull/73", + "state": "open", + "created_at": "2026-02-20T12:41:04Z", + "updated_at": "2026-02-20T12:42:03Z", + "closed_at": null, + "merged_at": null, + "head": "fix-ontology-validation", + "base": "main", + "draft": false, + "author": "calvinguo721" + }, + { + "number": 70, + "title": "windows安装程序打包", + "url": "https://github.com/666ghj/MiroFish/pull/70", + "state": "open", + "created_at": "2026-02-10T14:47:00Z", + "updated_at": "2026-02-16T20:17:26Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "Jonah-Wu23" + }, + { + "number": 33, + "title": "增加docker compose部署支持", + "url": "https://github.com/666ghj/MiroFish/pull/33", + "state": "closed", + "created_at": "2026-01-17T03:45:37Z", + "updated_at": "2026-01-29T01:24:09Z", + "closed_at": "2026-01-29T01:24:09Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "zouyonghe" + }, + { + "number": 38, + "title": "feat: Add support for Anthropic SDK (Claude) and multi-provider switching", + "url": "https://github.com/666ghj/MiroFish/pull/38", + "state": "open", + "created_at": "2026-01-20T09:56:00Z", + "updated_at": "2026-01-24T16:25:40Z", + "closed_at": null, + "merged_at": null, + "head": "feat/anthropic-sdk", + "base": "main", + "draft": false, + "author": "SmartisanNaive" + }, + { + "number": 25, + "title": "添加 Docker 支持和 CI/CD 自动化", + "url": "https://github.com/666ghj/MiroFish/pull/25", + "state": "closed", + "created_at": "2026-01-15T02:44:29Z", + "updated_at": "2026-01-22T10:32:32Z", + "closed_at": "2026-01-22T10:32:32Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "Deroino" + }, + { + "number": 44, + "title": "添加 docker 与 GitHub Actions", + "url": "https://github.com/666ghj/MiroFish/pull/44", + "state": "closed", + "created_at": "2026-01-21T02:43:22Z", + "updated_at": "2026-01-22T10:31:52Z", + "closed_at": "2026-01-22T10:31:52Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "moonhalf-nostar" + }, + { + "number": 49, + "title": "记忆图谱本地化实现", + "url": "https://github.com/666ghj/MiroFish/pull/49", + "state": "open", + "created_at": "2026-01-22T06:42:21Z", + "updated_at": "2026-01-22T06:42:21Z", + "closed_at": null, + "merged_at": null, + "head": "feat/local", + "base": "main", + "draft": false, + "author": "Momoyeyu" + }, + { + "number": 6, + "title": "新增 /projects 历史项目页、默认仅显示环境搭建完成项目、点击进入环境/项目feat(frontend): add projects history page", + "url": "https://github.com/666ghj/MiroFish/pull/6", + "state": "closed", + "created_at": "2025-12-26T15:21:46Z", + "updated_at": "2026-01-20T09:52:11Z", + "closed_at": "2026-01-20T09:52:11Z", + "merged_at": null, + "head": "feat/projects-history", + "base": "main", + "draft": false, + "author": "jwc19890114" + }, + { + "number": 15, + "title": "fix(frontend): handle simulation failed status", + "url": "https://github.com/666ghj/MiroFish/pull/15", + "state": "open", + "created_at": "2026-01-06T06:45:39Z", + "updated_at": "2026-01-06T06:53:51Z", + "closed_at": null, + "merged_at": null, + "head": "fix/frontend-simulation-error-handling", + "base": "main", + "draft": false, + "author": "tt-a1i" + }, + { + "number": 12, + "title": "Backend terminal color change", + "url": "https://github.com/666ghj/MiroFish/pull/12", + "state": "closed", + "created_at": "2025-12-30T10:04:33Z", + "updated_at": "2025-12-30T10:07:39Z", + "closed_at": "2025-12-30T10:05:36Z", + "merged_at": "2025-12-30T10:05:36Z", + "head": "cursor/backend-terminal-color-change-14fd", + "base": "main", + "draft": false, + "author": "666ghj" + }, + { + "number": 10, + "title": "Codebase bug resolution", + "url": "https://github.com/666ghj/MiroFish/pull/10", + "state": "closed", + "created_at": "2025-12-29T08:14:25Z", + "updated_at": "2025-12-30T09:59:16Z", + "closed_at": "2025-12-29T08:20:40Z", + "merged_at": null, + "head": "cursor/codebase-bug-resolution-07f6", + "base": "main", + "draft": true, + "author": "666ghj" + }, + { + "number": 1, + "title": " Windows 兼容性修复", + "url": "https://github.com/666ghj/MiroFish/pull/1", + "state": "closed", + "created_at": "2025-12-22T18:48:17Z", + "updated_at": "2025-12-30T09:58:27Z", + "closed_at": "2025-12-30T09:58:27Z", + "merged_at": null, + "head": "bugfix", + "base": "main", + "draft": false, + "author": "huanchong-99" + }, + { + "number": 2, + "title": "Encoding display fix", + "url": "https://github.com/666ghj/MiroFish/pull/2", + "state": "closed", + "created_at": "2025-12-22T19:53:01Z", + "updated_at": "2025-12-26T10:00:16Z", + "closed_at": "2025-12-26T10:00:16Z", + "merged_at": null, + "head": "encoding-display-fix", + "base": "main", + "draft": false, + "author": "huanchong-99" + } + ] +} diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md new file mode 100644 index 00000000..b7d8c2e9 --- /dev/null +++ b/docs/upstream-all-summary.md @@ -0,0 +1,33 @@ +# Upstream Triage Snapshot + +- Repository: `666ghj/MiroFish` +- State filter: `all` +- Captured: `2026-03-11T06:44:20.499587+00:00` +- Issues: `79` total (`open=32`, `closed=47`) +- Pull requests: `47` total (`open=35`, `closed=12`) + +## Recently Updated Issues + +- #121 [closed] 卡在了Exception in handleNewProject: Network Error (question) +- #123 [closed] プリセット業界知識RAGの導入(方式3: ローカルファイル注入) (no labels) +- #117 [open] ### Feature Request: English Language Support (enhancement) +- #110 [open] 阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用 (LLM API) +- #64 [open] 一直卡在上传文件错误:Request failed with status code 500 (no labels) +- #106 [open] 能否采用除了zep的别的知识图谱 (no labels) +- #109 [closed] 纯小白看到新闻后本机部署,但似乎Zep额度用完后不知道接下来咋办了 (question) +- #42 [open] 项目在3/5开始模拟时会消耗大量内存 (no labels) +- #84 [open] 报告生成失败,请问有没有办法重新生成? (question) +- #107 [open] 镜像问题 (no labels) + +## Recently Updated Pull Requests + +- #105 [open] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) +- #132 [open] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) +- #131 [open] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) +- #130 [open] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) +- #120 [open] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) +- #129 [open] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) +- #127 [open] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) +- #126 [open] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) +- #125 [open] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) +- #124 [open] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 677a7124..62f5d422 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,14 +1,24 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:38:00.348727+00:00", + "captured_at": "2026-03-11T06:44:19.616630+00:00", + "counts": { + "issues": { + "open": 32 + }, + "pull_requests": { + "open": 35 + } + }, "issues": [ { "number": 117, "title": "### Feature Request: English Language Support", "url": "https://github.com/666ghj/MiroFish/issues/117", + "state": "open", "created_at": "2026-03-10T08:44:18Z", "updated_at": "2026-03-10T08:46:24Z", + "closed_at": null, "labels": [ "enhancement" ], @@ -18,37 +28,80 @@ "number": 110, "title": "阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用", "url": "https://github.com/666ghj/MiroFish/issues/110", + "state": "open", "created_at": "2026-03-10T01:08:29Z", "updated_at": "2026-03-10T06:40:37Z", + "closed_at": null, "labels": [ "LLM API" ], "author": "weilb" }, { - "number": 107, - "title": "镜像问题", - "url": "https://github.com/666ghj/MiroFish/issues/107", - "created_at": "2026-03-09T14:44:45Z", - "updated_at": "2026-03-09T14:44:45Z", + "number": 64, + "title": "一直卡在上传文件错误:Request failed with status code 500", + "url": "https://github.com/666ghj/MiroFish/issues/64", + "state": "open", + "created_at": "2026-01-31T13:10:06Z", + "updated_at": "2026-03-10T05:40:36Z", + "closed_at": null, "labels": [], - "author": "zhuhw19" + "author": "G-LJDS2022" }, { "number": 106, "title": "能否采用除了zep的别的知识图谱", "url": "https://github.com/666ghj/MiroFish/issues/106", + "state": "open", "created_at": "2026-03-09T13:55:59Z", "updated_at": "2026-03-10T02:33:21Z", + "closed_at": null, "labels": [], "author": "paipaiio" }, + { + "number": 42, + "title": "项目在3/5开始模拟时会消耗大量内存", + "url": "https://github.com/666ghj/MiroFish/issues/42", + "state": "open", + "created_at": "2026-01-21T01:57:50Z", + "updated_at": "2026-03-09T17:28:20Z", + "closed_at": null, + "labels": [], + "author": "s1f102500012" + }, + { + "number": 84, + "title": "报告生成失败,请问有没有办法重新生成?", + "url": "https://github.com/666ghj/MiroFish/issues/84", + "state": "open", + "created_at": "2026-03-08T08:10:41Z", + "updated_at": "2026-03-09T17:26:28Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "luchenwei9266" + }, + { + "number": 107, + "title": "镜像问题", + "url": "https://github.com/666ghj/MiroFish/issues/107", + "state": "open", + "created_at": "2026-03-09T14:44:45Z", + "updated_at": "2026-03-09T14:44:45Z", + "closed_at": null, + "labels": [], + "author": "zhuhw19" + }, { "number": 99, "title": "Docker镜像没有arm版本", "url": "https://github.com/666ghj/MiroFish/issues/99", + "state": "open", "created_at": "2026-03-09T06:52:35Z", "updated_at": "2026-03-09T06:54:58Z", + "closed_at": null, "labels": [ "enhancement" ], @@ -58,8 +111,10 @@ "number": 93, "title": "`frontend/src/api/index.js`中的`baseURL`不应该硬编码", "url": "https://github.com/666ghj/MiroFish/issues/93", + "state": "open", "created_at": "2026-03-08T16:44:24Z", "updated_at": "2026-03-09T01:53:47Z", + "closed_at": null, "labels": [ "enhancement" ], @@ -69,126 +124,161 @@ "number": 92, "title": "Upgrade GitHub Actions", "url": "https://github.com/666ghj/MiroFish/issues/92", + "state": "open", "created_at": "2026-03-08T15:26:04Z", "updated_at": "2026-03-08T15:28:09Z", + "closed_at": null, "labels": [ "enhancement" ], "author": "leon-x-labs" }, { - "number": 84, - "title": "报告生成失败,请问有没有办法重新生成?", - "url": "https://github.com/666ghj/MiroFish/issues/84", - "created_at": "2026-03-08T08:10:41Z", - "updated_at": "2026-03-09T17:26:28Z", + "number": 56, + "title": "Zep 本地化实现方案交流专贴", + "url": "https://github.com/666ghj/MiroFish/issues/56", + "state": "open", + "created_at": "2026-01-23T07:24:57Z", + "updated_at": "2026-03-06T01:40:22Z", + "closed_at": null, + "labels": [], + "author": "666ghj" + }, + { + "number": 68, + "title": "尝试进行首次模拟,等待了1夜还是在3/5的阶段", + "url": "https://github.com/666ghj/MiroFish/issues/68", + "state": "open", + "created_at": "2026-02-10T01:19:08Z", + "updated_at": "2026-03-01T08:29:56Z", + "closed_at": null, "labels": [ "question" ], - "author": "luchenwei9266" + "author": "GarretRen" + }, + { + "number": 75, + "title": "Zep 的免费限速会让进度卡99%", + "url": "https://github.com/666ghj/MiroFish/issues/75", + "state": "open", + "created_at": "2026-02-26T08:35:41Z", + "updated_at": "2026-02-28T08:13:33Z", + "closed_at": null, + "labels": [], + "author": "fengkuangyibo" }, { "number": 76, "title": "知识图谱构建提供接入 ragflow api 的功能", "url": "https://github.com/666ghj/MiroFish/issues/76", + "state": "open", "created_at": "2026-02-27T12:02:39Z", "updated_at": "2026-02-28T08:02:11Z", + "closed_at": null, "labels": [ "Memory Layer" ], "author": "Hitomogami" }, { - "number": 75, - "title": "Zep 的免费限速会让进度卡99%", - "url": "https://github.com/666ghj/MiroFish/issues/75", - "created_at": "2026-02-26T08:35:41Z", - "updated_at": "2026-02-28T08:13:33Z", + "number": 9, + "title": "可以设置中断重新加载吗", + "url": "https://github.com/666ghj/MiroFish/issues/9", + "state": "open", + "created_at": "2025-12-28T13:16:54Z", + "updated_at": "2026-02-21T09:55:20Z", + "closed_at": null, "labels": [], - "author": "fengkuangyibo" + "author": "LMG-arch" }, { "number": 69, "title": "模型对接", "url": "https://github.com/666ghj/MiroFish/issues/69", + "state": "open", "created_at": "2026-02-10T07:53:43Z", "updated_at": "2026-02-10T07:56:20Z", + "closed_at": null, "labels": [ "question" ], "author": "wjh-w" }, { - "number": 68, - "title": "尝试进行首次模拟,等待了1夜还是在3/5的阶段", - "url": "https://github.com/666ghj/MiroFish/issues/68", - "created_at": "2026-02-10T01:19:08Z", - "updated_at": "2026-03-01T08:29:56Z", - "labels": [ - "question" - ], - "author": "GarretRen" - }, - { - "number": 64, - "title": "一直卡在上传文件错误:Request failed with status code 500", - "url": "https://github.com/666ghj/MiroFish/issues/64", - "created_at": "2026-01-31T13:10:06Z", - "updated_at": "2026-03-10T05:40:36Z", + "number": 37, + "title": "模拟环境未运行或已关闭,无法执行Interview: sim_66f01bcf8013。模拟环境可能已关闭,请确保OASIS环境正在运行。", + "url": "https://github.com/666ghj/MiroFish/issues/37", + "state": "open", + "created_at": "2026-01-20T09:10:49Z", + "updated_at": "2026-02-09T04:54:14Z", + "closed_at": null, "labels": [], - "author": "G-LJDS2022" + "author": "Ezj-Amon" }, { - "number": 62, - "title": "很好的创意,专门注册来提提问题和建议啦", - "url": "https://github.com/666ghj/MiroFish/issues/62", - "created_at": "2026-01-28T01:39:38Z", - "updated_at": "2026-01-28T08:34:36Z", + "number": 60, + "title": "Zep 免费计划 429 限流导致图谱构建失败(请求过密)", + "url": "https://github.com/666ghj/MiroFish/issues/60", + "state": "open", + "created_at": "2026-01-24T16:03:41Z", + "updated_at": "2026-01-28T08:36:57Z", + "closed_at": null, "labels": [], - "author": "piaopiaomiaomiao" + "author": "Jonah-Wu23" }, { "number": 61, "title": "能否将修改api的功能在前端也实现", "url": "https://github.com/666ghj/MiroFish/issues/61", + "state": "open", "created_at": "2026-01-27T13:37:15Z", "updated_at": "2026-01-28T08:35:08Z", + "closed_at": null, "labels": [], "author": "skoa323" }, { - "number": 60, - "title": "Zep 免费计划 429 限流导致图谱构建失败(请求过密)", - "url": "https://github.com/666ghj/MiroFish/issues/60", - "created_at": "2026-01-24T16:03:41Z", - "updated_at": "2026-01-28T08:36:57Z", + "number": 62, + "title": "很好的创意,专门注册来提提问题和建议啦", + "url": "https://github.com/666ghj/MiroFish/issues/62", + "state": "open", + "created_at": "2026-01-28T01:39:38Z", + "updated_at": "2026-01-28T08:34:36Z", + "closed_at": null, "labels": [], - "author": "Jonah-Wu23" + "author": "piaopiaomiaomiao" }, { "number": 58, "title": "使用ollama加载的本地大模型启动引擎时经常会遇到超时问题", "url": "https://github.com/666ghj/MiroFish/issues/58", + "state": "open", "created_at": "2026-01-24T10:47:13Z", "updated_at": "2026-01-24T16:18:14Z", + "closed_at": null, "labels": [], "author": "ThomasWang071001" }, { - "number": 56, - "title": "Zep 本地化实现方案交流专贴", - "url": "https://github.com/666ghj/MiroFish/issues/56", - "created_at": "2026-01-23T07:24:57Z", - "updated_at": "2026-03-06T01:40:22Z", + "number": 46, + "title": "npm安装依赖和配置提示project.license` as a TOML table is deprecated", + "url": "https://github.com/666ghj/MiroFish/issues/46", + "state": "open", + "created_at": "2026-01-21T12:26:05Z", + "updated_at": "2026-01-23T10:34:52Z", + "closed_at": null, "labels": [], - "author": "666ghj" + "author": "Vamco2022" }, { "number": 55, "title": "做了一个基于本地neo4j的版本", "url": "https://github.com/666ghj/MiroFish/issues/55", + "state": "open", "created_at": "2026-01-23T03:08:03Z", "updated_at": "2026-01-23T06:27:04Z", + "closed_at": null, "labels": [], "author": "xumengke2025-sys" }, @@ -196,8 +286,10 @@ "number": 54, "title": "太喜欢你这个项目了!给了我巨大的帮助!", "url": "https://github.com/666ghj/MiroFish/issues/54", + "state": "open", "created_at": "2026-01-23T02:39:53Z", "updated_at": "2026-01-23T02:39:53Z", + "closed_at": null, "labels": [], "author": "zb2947244682" }, @@ -205,26 +297,32 @@ "number": 52, "title": "API最大长度超过导致程序奔溃", "url": "https://github.com/666ghj/MiroFish/issues/52", + "state": "open", "created_at": "2026-01-22T13:25:33Z", "updated_at": "2026-01-22T13:25:33Z", + "closed_at": null, "labels": [], "author": "ngyygm" }, { - "number": 46, - "title": "npm安装依赖和配置提示project.license` as a TOML table is deprecated", - "url": "https://github.com/666ghj/MiroFish/issues/46", - "created_at": "2026-01-21T12:26:05Z", - "updated_at": "2026-01-23T10:34:52Z", + "number": 24, + "title": "ERROR: 报告生成失败: 'NoneType' object is not subscriptable", + "url": "https://github.com/666ghj/MiroFish/issues/24", + "state": "open", + "created_at": "2026-01-14T15:53:08Z", + "updated_at": "2026-01-21T13:28:41Z", + "closed_at": null, "labels": [], - "author": "Vamco2022" + "author": "Joe-rq" }, { "number": 45, "title": "与世界中任意个体对话功能和发送调查问卷到世界中 两个功能报错 IPC 响应 failed", "url": "https://github.com/666ghj/MiroFish/issues/45", + "state": "open", "created_at": "2026-01-21T06:46:41Z", "updated_at": "2026-01-21T07:11:18Z", + "closed_at": null, "labels": [], "author": "LucasXu666666" }, @@ -232,62 +330,43 @@ "number": 43, "title": "在使用时调用IPC超时", "url": "https://github.com/666ghj/MiroFish/issues/43", + "state": "open", "created_at": "2026-01-21T02:23:35Z", "updated_at": "2026-01-21T07:10:12Z", + "closed_at": null, "labels": [], "author": "dbplayer-git" }, { - "number": 42, - "title": "项目在3/5开始模拟时会消耗大量内存", - "url": "https://github.com/666ghj/MiroFish/issues/42", - "created_at": "2026-01-21T01:57:50Z", - "updated_at": "2026-03-09T17:28:20Z", - "labels": [], - "author": "s1f102500012" - }, - { - "number": 37, - "title": "模拟环境未运行或已关闭,无法执行Interview: sim_66f01bcf8013。模拟环境可能已关闭,请确保OASIS环境正在运行。", - "url": "https://github.com/666ghj/MiroFish/issues/37", - "created_at": "2026-01-20T09:10:49Z", - "updated_at": "2026-02-09T04:54:14Z", - "labels": [], - "author": "Ezj-Amon" - }, - { - "number": 24, - "title": "ERROR: 报告生成失败: 'NoneType' object is not subscriptable", - "url": "https://github.com/666ghj/MiroFish/issues/24", - "created_at": "2026-01-14T15:53:08Z", - "updated_at": "2026-01-21T13:28:41Z", + "number": 19, + "title": "建议初次使用不用太大的pdf", + "url": "https://github.com/666ghj/MiroFish/issues/19", + "state": "open", + "created_at": "2026-01-14T02:45:19Z", + "updated_at": "2026-01-15T05:57:37Z", + "closed_at": null, "labels": [], - "author": "Joe-rq" + "author": "paperplane123" }, { "number": 21, "title": "部署在群辉服务器上,docker里启动了服务,然后用过反向代理可以访问前端了,如果已经开始模拟了,刷新网页或者关掉再打开会发生什么", "url": "https://github.com/666ghj/MiroFish/issues/21", + "state": "open", "created_at": "2026-01-14T08:33:53Z", "updated_at": "2026-01-14T08:33:53Z", + "closed_at": null, "labels": [], "author": "usernametooshort" }, - { - "number": 19, - "title": "建议初次使用不用太大的pdf", - "url": "https://github.com/666ghj/MiroFish/issues/19", - "created_at": "2026-01-14T02:45:19Z", - "updated_at": "2026-01-15T05:57:37Z", - "labels": [], - "author": "paperplane123" - }, { "number": 17, "title": "多次仿真 + 元报告共识,提升预测结果的可信度", "url": "https://github.com/666ghj/MiroFish/issues/17", + "state": "open", "created_at": "2026-01-06T09:07:51Z", "updated_at": "2026-01-06T09:07:51Z", + "closed_at": null, "labels": [], "author": "tt-a1i" }, @@ -295,28 +374,38 @@ "number": 14, "title": "Frontend doesn't show error when simulation fails", "url": "https://github.com/666ghj/MiroFish/issues/14", + "state": "open", "created_at": "2026-01-05T11:43:44Z", "updated_at": "2026-01-06T06:15:22Z", + "closed_at": null, "labels": [], "author": "tt-a1i" - }, - { - "number": 9, - "title": "可以设置中断重新加载吗", - "url": "https://github.com/666ghj/MiroFish/issues/9", - "created_at": "2025-12-28T13:16:54Z", - "updated_at": "2026-02-21T09:55:20Z", - "labels": [], - "author": "LMG-arch" } ], "pull_requests": [ + { + "number": 105, + "title": "fix: security improvements and error handling fixes", + "url": "https://github.com/666ghj/MiroFish/pull/105", + "state": "open", + "created_at": "2026-03-09T11:57:58Z", + "updated_at": "2026-03-11T05:48:53Z", + "closed_at": null, + "merged_at": null, + "head": "fix/security-improvements", + "base": "main", + "draft": false, + "author": "hobostay" + }, { "number": 132, "title": "docs:add simple system architecture part for README-EN.md & README.md", "url": "https://github.com/666ghj/MiroFish/pull/132", + "state": "open", "created_at": "2026-03-11T05:45:53Z", "updated_at": "2026-03-11T05:47:00Z", + "closed_at": null, + "merged_at": null, "head": "docs/add-sys-architecture-part", "base": "main", "draft": false, @@ -326,8 +415,11 @@ "number": 131, "title": "feat(graph_builder): add retry mechanism for Zep Cloud connection failures", "url": "https://github.com/666ghj/MiroFish/pull/131", + "state": "open", "created_at": "2026-03-11T05:42:07Z", "updated_at": "2026-03-11T05:43:10Z", + "closed_at": null, + "merged_at": null, "head": "feat/zep-retry-mechanism", "base": "main", "draft": false, @@ -337,19 +429,39 @@ "number": 130, "title": "docs: 添加贡献指南文档", "url": "https://github.com/666ghj/MiroFish/pull/130", + "state": "open", "created_at": "2026-03-11T04:24:56Z", "updated_at": "2026-03-11T04:26:00Z", + "closed_at": null, + "merged_at": null, "head": "docs/add-pr-guide", "base": "main", "draft": false, "author": "M-Tlinqinming" }, + { + "number": 120, + "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", + "url": "https://github.com/666ghj/MiroFish/pull/120", + "state": "open", + "created_at": "2026-03-10T15:41:04Z", + "updated_at": "2026-03-11T03:54:11Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "28764116" + }, { "number": 129, "title": "fix(report_agent): handle API token overflow crash with context lengt…", "url": "https://github.com/666ghj/MiroFish/pull/129", + "state": "open", "created_at": "2026-03-11T02:55:33Z", "updated_at": "2026-03-11T02:56:38Z", + "closed_at": null, + "merged_at": null, "head": "fix/fix-priority-issues-mNNjT", "base": "main", "draft": false, @@ -359,8 +471,11 @@ "number": 127, "title": "Fix potential crash in LLMClient when content is None", "url": "https://github.com/666ghj/MiroFish/pull/127", + "state": "open", "created_at": "2026-03-10T22:43:33Z", "updated_at": "2026-03-10T22:44:42Z", + "closed_at": null, + "merged_at": null, "head": "fix/llm-client-none-content", "base": "main", "draft": false, @@ -370,8 +485,11 @@ "number": 126, "title": "feat: Add custom exceptions and enhanced config validation", "url": "https://github.com/666ghj/MiroFish/pull/126", + "state": "open", "created_at": "2026-03-10T22:12:22Z", "updated_at": "2026-03-10T22:13:37Z", + "closed_at": null, + "merged_at": null, "head": "feature/custom-exceptions-and-config-validation", "base": "main", "draft": false, @@ -381,8 +499,11 @@ "number": 125, "title": "fix: improve new-project network error diagnostics", "url": "https://github.com/666ghj/MiroFish/pull/125", + "state": "open", "created_at": "2026-03-10T21:50:43Z", "updated_at": "2026-03-10T21:51:51Z", + "closed_at": null, + "merged_at": null, "head": "fix/issue-121", "base": "main", "draft": false, @@ -392,8 +513,11 @@ "number": 124, "title": "fix: robust JSON extraction for mixed LLM responses", "url": "https://github.com/666ghj/MiroFish/pull/124", + "state": "open", "created_at": "2026-03-10T21:50:31Z", "updated_at": "2026-03-10T21:51:46Z", + "closed_at": null, + "merged_at": null, "head": "fix/issue-64", "base": "main", "draft": false, @@ -403,30 +527,25 @@ "number": 122, "title": "fix(llm_client): remove response_format json_object for local LLM compatibility", "url": "https://github.com/666ghj/MiroFish/pull/122", + "state": "open", "created_at": "2026-03-10T18:20:49Z", "updated_at": "2026-03-10T18:33:48Z", + "closed_at": null, + "merged_at": null, "head": "fix/lm-studio-json-object-compat", "base": "main", "draft": false, "author": "ImL1s" }, - { - "number": 120, - "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", - "url": "https://github.com/666ghj/MiroFish/pull/120", - "created_at": "2026-03-10T15:41:04Z", - "updated_at": "2026-03-11T03:54:11Z", - "head": "main", - "base": "main", - "draft": false, - "author": "28764116" - }, { "number": 119, "title": "feat: add an option to switch to english language", "url": "https://github.com/666ghj/MiroFish/pull/119", + "state": "open", "created_at": "2026-03-10T15:05:40Z", "updated_at": "2026-03-10T18:14:33Z", + "closed_at": null, + "merged_at": null, "head": "language-option", "base": "main", "draft": false, @@ -436,8 +555,11 @@ "number": 118, "title": "feat(ragflow): add RAGflow as alternative graph backend with full pip…", "url": "https://github.com/666ghj/MiroFish/pull/118", + "state": "open", "created_at": "2026-03-10T09:29:33Z", "updated_at": "2026-03-10T09:30:44Z", + "closed_at": null, + "merged_at": null, "head": "fix/ragflow-pattern-compliance", "base": "main", "draft": false, @@ -447,8 +569,11 @@ "number": 116, "title": "Upgrade GitHub Actions", "url": "https://github.com/666ghj/MiroFish/pull/116", + "state": "open", "created_at": "2026-03-10T07:30:38Z", "updated_at": "2026-03-10T07:30:42Z", + "closed_at": null, + "merged_at": null, "head": "chore/upgrade-actions", "base": "main", "draft": false, @@ -458,8 +583,11 @@ "number": 115, "title": "Use SPDX license string", "url": "https://github.com/666ghj/MiroFish/pull/115", + "state": "open", "created_at": "2026-03-10T07:28:37Z", "updated_at": "2026-03-10T07:28:41Z", + "closed_at": null, + "merged_at": null, "head": "fix/pyproject-license", "base": "main", "draft": false, @@ -469,8 +597,11 @@ "number": 114, "title": "Fix API base URL fallback", "url": "https://github.com/666ghj/MiroFish/pull/114", + "state": "open", "created_at": "2026-03-10T07:21:29Z", "updated_at": "2026-03-10T07:21:49Z", + "closed_at": null, + "merged_at": null, "head": "fix/api-baseurl-default", "base": "main", "draft": false, @@ -480,8 +611,11 @@ "number": 113, "title": "docs(readme): add Japanese README", "url": "https://github.com/666ghj/MiroFish/pull/113", + "state": "open", "created_at": "2026-03-10T06:43:16Z", "updated_at": "2026-03-10T06:44:34Z", + "closed_at": null, + "merged_at": null, "head": "add-ja-doc", "base": "main", "draft": false, @@ -491,41 +625,53 @@ "number": 112, "title": "Korean README.md added", "url": "https://github.com/666ghj/MiroFish/pull/112", + "state": "open", "created_at": "2026-03-10T05:25:01Z", "updated_at": "2026-03-10T05:25:55Z", + "closed_at": null, + "merged_at": null, "head": "main", "base": "main", "draft": false, "author": "waitle" }, + { + "number": 72, + "title": "清理模型返回的markdown标记", + "url": "https://github.com/666ghj/MiroFish/pull/72", + "state": "open", + "created_at": "2026-02-15T05:27:05Z", + "updated_at": "2026-03-10T02:58:45Z", + "closed_at": null, + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "MoeclubM" + }, { "number": 108, "title": "feat(installer): add Windows installer build scripts", "url": "https://github.com/666ghj/MiroFish/pull/108", + "state": "open", "created_at": "2026-03-09T17:14:55Z", "updated_at": "2026-03-09T17:16:21Z", + "closed_at": null, + "merged_at": null, "head": "feat/windows-installer", "base": "main", "draft": false, "author": "JasonOA888" }, - { - "number": 105, - "title": "fix: security improvements and error handling fixes", - "url": "https://github.com/666ghj/MiroFish/pull/105", - "created_at": "2026-03-09T11:57:58Z", - "updated_at": "2026-03-11T05:48:53Z", - "head": "fix/security-improvements", - "base": "main", - "draft": false, - "author": "hobostay" - }, { "number": 104, "title": "fix: make vite proxy target configurable via environment variable", "url": "https://github.com/666ghj/MiroFish/pull/104", + "state": "open", "created_at": "2026-03-09T09:05:37Z", "updated_at": "2026-03-09T09:06:54Z", + "closed_at": null, + "merged_at": null, "head": "fix/remove-hardcoded-api-url", "base": "main", "draft": false, @@ -535,8 +681,11 @@ "number": 103, "title": "ci: upgrade GitHub Actions and add ARM64 Docker support", "url": "https://github.com/666ghj/MiroFish/pull/103", + "state": "open", "created_at": "2026-03-09T09:03:45Z", "updated_at": "2026-03-09T09:04:59Z", + "closed_at": null, + "merged_at": null, "head": "fix/upgrade-actions-and-arm-support", "base": "main", "draft": false, @@ -546,8 +695,11 @@ "number": 102, "title": "fix(ci): add multi-platform Docker build for ARM64 support", "url": "https://github.com/666ghj/MiroFish/pull/102", + "state": "open", "created_at": "2026-03-09T08:25:27Z", "updated_at": "2026-03-09T08:26:30Z", + "closed_at": null, + "merged_at": null, "head": "fix/docker-multiplatform", "base": "main", "draft": false, @@ -557,8 +709,11 @@ "number": 101, "title": "feat(utils): add json_utils module for robust LLM JSON parsing", "url": "https://github.com/666ghj/MiroFish/pull/101", + "state": "open", "created_at": "2026-03-09T08:23:07Z", "updated_at": "2026-03-09T08:24:20Z", + "closed_at": null, + "merged_at": null, "head": "feat/json-utils-helper", "base": "main", "draft": false, @@ -568,8 +723,11 @@ "number": 100, "title": "fix(frontend): use relative baseURL in production, avoid hardcoded localhost", "url": "https://github.com/666ghj/MiroFish/pull/100", + "state": "open", "created_at": "2026-03-09T08:19:23Z", "updated_at": "2026-03-09T08:20:38Z", + "closed_at": null, + "merged_at": null, "head": "fix/frontend-baseurl", "base": "main", "draft": false, @@ -579,8 +737,11 @@ "number": 87, "title": "Upgrade GitHub Actions to latest versions", "url": "https://github.com/666ghj/MiroFish/pull/87", + "state": "open", "created_at": "2026-03-08T09:09:13Z", "updated_at": "2026-03-08T09:09:19Z", + "closed_at": null, + "merged_at": null, "head": "upgrade-github-actions-node24-general", "base": "main", "draft": false, @@ -590,8 +751,11 @@ "number": 86, "title": "Upgrade GitHub Actions for Node 24 compatibility", "url": "https://github.com/666ghj/MiroFish/pull/86", + "state": "open", "created_at": "2026-03-08T09:09:10Z", "updated_at": "2026-03-08T09:09:14Z", + "closed_at": null, + "merged_at": null, "head": "upgrade-github-actions-node24", "base": "main", "draft": false, @@ -601,8 +765,11 @@ "number": 82, "title": "[Security] Fix CRITICAL vulnerability: CVE-2025-64712", "url": "https://github.com/666ghj/MiroFish/pull/82", + "state": "open", "created_at": "2026-03-08T02:45:42Z", "updated_at": "2026-03-08T02:45:46Z", + "closed_at": null, + "merged_at": null, "head": "fix-cve-2025-64712-unstructured", "base": "main", "draft": false, @@ -612,8 +779,11 @@ "number": 81, "title": "feat: add configurable API timeout for slow local LLMs", "url": "https://github.com/666ghj/MiroFish/pull/81", + "state": "open", "created_at": "2026-03-08T02:34:41Z", "updated_at": "2026-03-08T02:35:36Z", + "closed_at": null, + "merged_at": null, "head": "fix/issue-58-configurable-timeout", "base": "main", "draft": false, @@ -623,8 +793,11 @@ "number": 74, "title": "fix: replace 4 bare excepts with except Exception", "url": "https://github.com/666ghj/MiroFish/pull/74", + "state": "open", "created_at": "2026-02-25T03:01:43Z", "updated_at": "2026-02-25T09:20:00Z", + "closed_at": null, + "merged_at": null, "head": "fix/bare-excepts", "base": "main", "draft": false, @@ -634,63 +807,67 @@ "number": 73, "title": "fix: Handle string entities/edges in _validate_and_process", "url": "https://github.com/666ghj/MiroFish/pull/73", + "state": "open", "created_at": "2026-02-20T12:41:04Z", "updated_at": "2026-02-20T12:42:03Z", + "closed_at": null, + "merged_at": null, "head": "fix-ontology-validation", "base": "main", "draft": false, "author": "calvinguo721" }, - { - "number": 72, - "title": "清理模型返回的markdown标记", - "url": "https://github.com/666ghj/MiroFish/pull/72", - "created_at": "2026-02-15T05:27:05Z", - "updated_at": "2026-03-10T02:58:45Z", - "head": "main", - "base": "main", - "draft": false, - "author": "MoeclubM" - }, { "number": 70, "title": "windows安装程序打包", "url": "https://github.com/666ghj/MiroFish/pull/70", + "state": "open", "created_at": "2026-02-10T14:47:00Z", "updated_at": "2026-02-16T20:17:26Z", + "closed_at": null, + "merged_at": null, "head": "main", "base": "main", "draft": false, "author": "Jonah-Wu23" }, - { - "number": 49, - "title": "记忆图谱本地化实现", - "url": "https://github.com/666ghj/MiroFish/pull/49", - "created_at": "2026-01-22T06:42:21Z", - "updated_at": "2026-01-22T06:42:21Z", - "head": "feat/local", - "base": "main", - "draft": false, - "author": "Momoyeyu" - }, { "number": 38, "title": "feat: Add support for Anthropic SDK (Claude) and multi-provider switching", "url": "https://github.com/666ghj/MiroFish/pull/38", + "state": "open", "created_at": "2026-01-20T09:56:00Z", "updated_at": "2026-01-24T16:25:40Z", + "closed_at": null, + "merged_at": null, "head": "feat/anthropic-sdk", "base": "main", "draft": false, "author": "SmartisanNaive" }, + { + "number": 49, + "title": "记忆图谱本地化实现", + "url": "https://github.com/666ghj/MiroFish/pull/49", + "state": "open", + "created_at": "2026-01-22T06:42:21Z", + "updated_at": "2026-01-22T06:42:21Z", + "closed_at": null, + "merged_at": null, + "head": "feat/local", + "base": "main", + "draft": false, + "author": "Momoyeyu" + }, { "number": 15, "title": "fix(frontend): handle simulation failed status", "url": "https://github.com/666ghj/MiroFish/pull/15", + "state": "open", "created_at": "2026-01-06T06:45:39Z", "updated_at": "2026-01-06T06:53:51Z", + "closed_at": null, + "merged_at": null, "head": "fix/frontend-simulation-error-handling", "base": "main", "draft": false, diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 9d3d2df0..bfdb9f78 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -1,32 +1,33 @@ # Upstream Triage Snapshot - Repository: `666ghj/MiroFish` -- Captured: `2026-03-11T06:38:00.349207+00:00` -- Open issues: `32` -- Open pull requests: `35` +- State filter: `open` +- Captured: `2026-03-11T06:44:19.617195+00:00` +- Issues: `32` total (`open=32`, `closed=0`) +- Pull requests: `35` total (`open=35`, `closed=0`) ## Recently Updated Issues -- #117 ### Feature Request: English Language Support (enhancement) -- #110 阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用 (LLM API) -- #107 镜像问题 (no labels) -- #106 能否采用除了zep的别的知识图谱 (no labels) -- #99 Docker镜像没有arm版本 (enhancement) -- #93 `frontend/src/api/index.js`中的`baseURL`不应该硬编码 (enhancement) -- #92 Upgrade GitHub Actions (enhancement) -- #84 报告生成失败,请问有没有办法重新生成? (question) -- #76 知识图谱构建提供接入 ragflow api 的功能 (Memory Layer) -- #75 Zep 的免费限速会让进度卡99% (no labels) +- #117 [open] ### Feature Request: English Language Support (enhancement) +- #110 [open] 阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用 (LLM API) +- #64 [open] 一直卡在上传文件错误:Request failed with status code 500 (no labels) +- #106 [open] 能否采用除了zep的别的知识图谱 (no labels) +- #42 [open] 项目在3/5开始模拟时会消耗大量内存 (no labels) +- #84 [open] 报告生成失败,请问有没有办法重新生成? (question) +- #107 [open] 镜像问题 (no labels) +- #99 [open] Docker镜像没有arm版本 (enhancement) +- #93 [open] `frontend/src/api/index.js`中的`baseURL`不应该硬编码 (enhancement) +- #92 [open] Upgrade GitHub Actions (enhancement) -## Open Pull Requests +## Recently Updated Pull Requests -- #132 docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) -- #131 feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) -- #130 docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) -- #129 fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) -- #127 Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) -- #126 feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) -- #125 fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) -- #124 fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) -- #122 fix(llm_client): remove response_format json_object for local LLM compatibility (`fix/lm-studio-json-object-compat` -> `main`) -- #120 fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) +- #105 [open] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) +- #132 [open] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) +- #131 [open] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) +- #130 [open] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) +- #120 [open] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) +- #129 [open] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) +- #127 [open] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) +- #126 [open] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) +- #125 [open] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) +- #124 [open] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 481cd439..95318686 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -4,7 +4,7 @@ Last refreshed: `2026-03-11` ## Current focus -- Keep a reusable local snapshot of `666ghj/MiroFish` open issues and pull requests. +- Keep reusable local snapshots of `666ghj/MiroFish` open and full issue/PR state. - Land small, low-risk upstream fixes before considering larger feature branches. - Make backend compatibility with OpenAI-compatible providers explicit in code and docs. @@ -18,6 +18,8 @@ Last refreshed: `2026-03-11` - `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. - `#127` Handle `None` response content: safe guard against provider edge cases. - `#129` Safe subset landed locally: configurable `LLM_MAX_TOKENS`, automatic retry after context-length failures, and report-agent message pruning to reduce overflow crashes. +- `#130` Add `CONTRIBUTING.md`: safe docs-only cherry-pick. +- `#132` Add README architecture overview: safe docs-only cherry-pick. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. ## Deferred for later review @@ -26,11 +28,18 @@ Last refreshed: `2026-03-11` - `#105` Security and error-handling sweep: high-value, but touches multiple API surfaces and config defaults, so it needs a dedicated pass instead of bundling into a low-risk cherry-pick cycle. ## Validation status +- `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py -q` passes with targeted regression coverage for context-length retry and default token configuration. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. - Follow-up is tracked in local beads issue `mirofish-ba6` to establish a lighter backend validation path. +## Snapshot artifacts + +- `docs/upstream-open-state.json` and `docs/upstream-open-summary.md` remain the fast open-work triage view. +- `docs/upstream-all-state.json` and `docs/upstream-all-summary.md` now capture the full upstream issue/PR state for historical triage and mirroring decisions. +- `scripts/sync_upstream_github.py` now supports paginated `--state all` refreshes and uses `GITHUB_TOKEN` / `GH_TOKEN` when available to avoid GitHub API rate-limit failures. + ## Practical mirror strategy for the fork - Mirror the highest-signal upstream PR branches to the fork when they are under active review. diff --git a/scripts/sync_upstream_github.py b/scripts/sync_upstream_github.py index df5524d3..e6599442 100644 --- a/scripts/sync_upstream_github.py +++ b/scripts/sync_upstream_github.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Fetch upstream GitHub issues and pull requests into a local summary.""" +"""Fetch upstream GitHub issues and pull requests into local summaries.""" from __future__ import annotations @@ -9,14 +9,28 @@ import sys import urllib.parse import urllib.request +from urllib.error import HTTPError from datetime import datetime, timezone from pathlib import Path +from typing import Any def fetch_json(url: str) -> object: - request = urllib.request.Request(url, headers={"User-Agent": "mirofish-upstream-sync"}) - with urllib.request.urlopen(request) as response: - return json.load(response) + headers = {"User-Agent": "mirofish-upstream-sync"} + token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") + if token: + headers["Authorization"] = f"Bearer {token}" + + request = urllib.request.Request(url, headers=headers) + try: + with urllib.request.urlopen(request) as response: + return json.load(response) + except HTTPError as exc: + if exc.code == 403 and "rate limit" in str(exc).lower(): + raise RuntimeError( + "GitHub API rate limit exceeded. Set GITHUB_TOKEN or GH_TOKEN before running sync." + ) from exc + raise def github_api(path: str, params: dict[str, object]) -> object: @@ -24,13 +38,36 @@ def github_api(path: str, params: dict[str, object]) -> object: return fetch_json(f"https://api.github.com{path}?{query}") +def github_api_paginated(path: str, params: dict[str, object], limit: int) -> list[dict[str, Any]]: + items: list[dict[str, Any]] = [] + page = 1 + per_page = min(limit, 100) + + while len(items) < limit: + payload = github_api(path, {**params, "per_page": per_page, "page": page}) + if not isinstance(payload, list): + raise ValueError(f"Expected list payload from GitHub API for {path}, got {type(payload)!r}") + if not payload: + break + + items.extend(payload) + if len(payload) < per_page: + break + + page += 1 + + return items[:limit] + + def compact_issue(issue: dict[str, object]) -> dict[str, object]: return { "number": issue["number"], "title": issue["title"], "url": issue["html_url"], + "state": issue["state"], "created_at": issue["created_at"], "updated_at": issue["updated_at"], + "closed_at": issue.get("closed_at"), "labels": [label["name"] for label in issue.get("labels", [])], "author": issue.get("user", {}).get("login"), } @@ -41,8 +78,11 @@ def compact_pr(pr: dict[str, object]) -> dict[str, object]: "number": pr["number"], "title": pr["title"], "url": pr["html_url"], + "state": pr["state"], "created_at": pr["created_at"], "updated_at": pr["updated_at"], + "closed_at": pr.get("closed_at"), + "merged_at": pr.get("merged_at"), "head": pr.get("head", {}).get("ref"), "base": pr.get("base", {}).get("ref"), "draft": pr.get("draft", False), @@ -50,14 +90,25 @@ def compact_pr(pr: dict[str, object]) -> dict[str, object]: } -def write_summary(path: Path, repo: str, issues: list[dict[str, object]], prs: list[dict[str, object]]) -> None: +def summarize_counts(items: list[dict[str, object]]) -> dict[str, int]: + counts: dict[str, int] = {} + for item in items: + state = str(item.get("state", "unknown")) + counts[state] = counts.get(state, 0) + 1 + return counts + + +def write_summary(path: Path, repo: str, state: str, issues: list[dict[str, object]], prs: list[dict[str, object]]) -> None: + issue_counts = summarize_counts(issues) + pr_counts = summarize_counts(prs) lines = [ "# Upstream Triage Snapshot", "", f"- Repository: `{repo}`", + f"- State filter: `{state}`", f"- Captured: `{datetime.now(timezone.utc).isoformat()}`", - f"- Open issues: `{len(issues)}`", - f"- Open pull requests: `{len(prs)}`", + f"- Issues: `{len(issues)}` total (`open={issue_counts.get('open', 0)}`, `closed={issue_counts.get('closed', 0)}`)", + f"- Pull requests: `{len(prs)}` total (`open={pr_counts.get('open', 0)}`, `closed={pr_counts.get('closed', 0)}`)", "", "## Recently Updated Issues", "", @@ -65,11 +116,12 @@ def write_summary(path: Path, repo: str, issues: list[dict[str, object]], prs: l for issue in issues[:10]: labels = ", ".join(issue["labels"]) if issue["labels"] else "no labels" - lines.append(f"- #{issue['number']} {issue['title']} ({labels})") + lines.append(f"- #{issue['number']} [{issue['state']}] {issue['title']} ({labels})") - lines.extend(["", "## Open Pull Requests", ""]) + lines.extend(["", "## Recently Updated Pull Requests", ""]) for pr in prs[:10]: - lines.append(f"- #{pr['number']} {pr['title']} (`{pr['head']}` -> `{pr['base']}`)") + suffix = " merged" if pr.get("merged_at") else "" + lines.append(f"- #{pr['number']} [{pr['state']}{suffix}] {pr['title']} (`{pr['head']}` -> `{pr['base']}`)") path.parent.mkdir(parents=True, exist_ok=True) path.write_text("\n".join(lines) + "\n", encoding="utf-8") @@ -78,20 +130,22 @@ def write_summary(path: Path, repo: str, issues: list[dict[str, object]], prs: l def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--repo", default="666ghj/MiroFish", help="owner/repo to inspect") - parser.add_argument("--state", default="open", help="GitHub state filter") - parser.add_argument("--limit", type=int, default=100, help="Maximum items to fetch per collection") + parser.add_argument("--state", default="open", help="GitHub state filter (open, closed, or all)") + parser.add_argument("--limit", type=int, default=500, help="Maximum items to fetch per collection") parser.add_argument("--output", required=True, help="Path to write machine-readable JSON") parser.add_argument("--summary", required=True, help="Path to write markdown summary") args = parser.parse_args() owner, name = args.repo.split("/", 1) - issue_items = github_api( + issue_items = github_api_paginated( f"/repos/{owner}/{name}/issues", - {"state": args.state, "per_page": min(args.limit, 100)}, + {"state": args.state, "sort": "updated", "direction": "desc"}, + args.limit, ) - pr_items = github_api( + pr_items = github_api_paginated( f"/repos/{owner}/{name}/pulls", - {"state": args.state, "per_page": min(args.limit, 100)}, + {"state": args.state, "sort": "updated", "direction": "desc"}, + args.limit, ) issues = [compact_issue(item) for item in issue_items if "pull_request" not in item] @@ -100,6 +154,10 @@ def main() -> int: "repo": args.repo, "state": args.state, "captured_at": datetime.now(timezone.utc).isoformat(), + "counts": { + "issues": summarize_counts(issues), + "pull_requests": summarize_counts(prs), + }, "issues": issues, "pull_requests": prs, } @@ -107,7 +165,7 @@ def main() -> int: output_path = Path(args.output) output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") - write_summary(Path(args.summary), args.repo, issues, prs) + write_summary(Path(args.summary), args.repo, args.state, issues, prs) print( f"Captured {len(issues)} issues and {len(prs)} pull requests from {args.repo} " diff --git a/tests/test_sync_upstream_github.py b/tests/test_sync_upstream_github.py new file mode 100644 index 00000000..93d2fe67 --- /dev/null +++ b/tests/test_sync_upstream_github.py @@ -0,0 +1,74 @@ +import unittest +from pathlib import Path +from unittest.mock import patch +import importlib.util + + +def load_module(): + script_path = Path(__file__).resolve().parents[1] / "scripts" / "sync_upstream_github.py" + spec = importlib.util.spec_from_file_location("sync_upstream_github", script_path) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +sync_upstream_github = load_module() + + +class SyncUpstreamGithubTests(unittest.TestCase): + def test_github_api_paginated_collects_multiple_pages(self): + responses = [ + [{"number": n} for n in range(1, 101)], + [{"number": n} for n in range(101, 106)], + ] + + with patch.object(sync_upstream_github, "github_api", side_effect=responses) as mocked: + items = sync_upstream_github.github_api_paginated("/repos/test/repo/issues", {"state": "all"}, limit=105) + + self.assertEqual(items[0], {"number": 1}) + self.assertEqual(items[-1], {"number": 105}) + self.assertEqual(len(items), 105) + self.assertEqual(mocked.call_count, 2) + self.assertEqual(mocked.call_args_list[0].args[1]["page"], 1) + self.assertEqual(mocked.call_args_list[1].args[1]["page"], 2) + + def test_compact_records_include_state_fields(self): + issue = sync_upstream_github.compact_issue( + { + "number": 10, + "title": "Issue title", + "html_url": "https://example.test/issues/10", + "state": "closed", + "created_at": "2026-01-01T00:00:00Z", + "updated_at": "2026-01-02T00:00:00Z", + "closed_at": "2026-01-03T00:00:00Z", + "labels": [{"name": "bug"}], + "user": {"login": "alice"}, + } + ) + pr = sync_upstream_github.compact_pr( + { + "number": 11, + "title": "PR title", + "html_url": "https://example.test/pull/11", + "state": "closed", + "created_at": "2026-01-01T00:00:00Z", + "updated_at": "2026-01-02T00:00:00Z", + "closed_at": "2026-01-03T00:00:00Z", + "merged_at": "2026-01-03T00:00:01Z", + "head": {"ref": "feature"}, + "base": {"ref": "main"}, + "draft": False, + "user": {"login": "bob"}, + } + ) + + self.assertEqual(issue["state"], "closed") + self.assertEqual(issue["closed_at"], "2026-01-03T00:00:00Z") + self.assertEqual(pr["state"], "closed") + self.assertEqual(pr["merged_at"], "2026-01-03T00:00:01Z") + + +if __name__ == "__main__": + unittest.main() From 6dcea0b7152d739bbe6bff449abb5b9e3c34dd2a Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:48:36 +0000 Subject: [PATCH 012/373] fix: retry transient zep graph operations --- backend/app/config.py | 2 + backend/app/services/graph_builder.py | 133 ++++++++++++++++++++------ backend/tests/test_graph_builder.py | 127 ++++++++++++++++++++++++ docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-triage.md | 4 +- 6 files changed, 236 insertions(+), 34 deletions(-) create mode 100644 backend/tests/test_graph_builder.py diff --git a/backend/app/config.py b/backend/app/config.py index 451c258d..81b02641 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -44,6 +44,8 @@ class Config: # Zep配置 ZEP_API_KEY = os.environ.get('ZEP_API_KEY') + ZEP_RETRY_MAX_ATTEMPTS = int(os.environ.get('ZEP_RETRY_MAX_ATTEMPTS', '3')) + ZEP_RETRY_BASE_DELAY_SECONDS = float(os.environ.get('ZEP_RETRY_BASE_DELAY_SECONDS', '2')) # 文件上传配置 MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB diff --git a/backend/app/services/graph_builder.py b/backend/app/services/graph_builder.py index 0e0444bf..a4867ad1 100644 --- a/backend/app/services/graph_builder.py +++ b/backend/app/services/graph_builder.py @@ -15,6 +15,7 @@ from ..config import Config from ..models.task import TaskManager, TaskStatus +from ..utils.logger import get_logger from ..utils.zep_paging import fetch_all_nodes, fetch_all_edges from .text_processor import TextProcessor @@ -49,6 +50,67 @@ def __init__(self, api_key: Optional[str] = None): self.client = Zep(api_key=self.api_key) self.task_manager = TaskManager() + self.logger = get_logger('mirofish.graph_builder') + + @staticmethod + def _is_retryable_zep_error(error: Exception) -> bool: + """Return whether a Zep operation failure looks transient and safe to retry.""" + status_code = getattr(error, "status_code", None) + if status_code in {408, 409, 423, 425, 429, 500, 502, 503, 504}: + return True + + error_text = str(error).lower() + retry_signals = ( + "429", + "too many requests", + "rate limit", + "timeout", + "timed out", + "temporarily unavailable", + "service unavailable", + "bad gateway", + "gateway timeout", + "connection reset", + "connection aborted", + "connection error", + "remote disconnected", + ) + return any(signal in error_text for signal in retry_signals) + + def _retry_zep_operation( + self, + operation_name: str, + func: Callable[[], Any], + *, + max_retries: Optional[int] = None, + progress_callback: Optional[Callable[[str, float], None]] = None, + progress_message: Optional[Callable[[int, int, float], str]] = None, + progress_value: float = 0, + ) -> Any: + """Retry transient Zep failures with backoff while surfacing progress updates.""" + max_attempts = max_retries or Config.ZEP_RETRY_MAX_ATTEMPTS + base_delay = Config.ZEP_RETRY_BASE_DELAY_SECONDS + + for attempt in range(max_attempts): + try: + return func() + except Exception as error: + should_retry = attempt < max_attempts - 1 and self._is_retryable_zep_error(error) + if not should_retry: + raise + + wait_time = base_delay * (2 ** attempt) + self.logger.warning( + "%s failed on attempt %s/%s, retrying in %.1fs: %s", + operation_name, + attempt + 1, + max_attempts, + wait_time, + error, + ) + if progress_callback and progress_message: + progress_callback(progress_message(attempt + 1, max_attempts, wait_time), progress_value) + time.sleep(wait_time) def build_graph_async( self, @@ -184,19 +246,23 @@ def _build_graph_worker( error_msg = f"{str(e)}\n{traceback.format_exc()}" self.task_manager.fail_task(task_id, error_msg) - def create_graph(self, name: str) -> str: + def create_graph(self, name: str, max_retries: Optional[int] = None) -> str: """创建Zep图谱(公开方法)""" graph_id = f"mirofish_{uuid.uuid4().hex[:16]}" - - self.client.graph.create( - graph_id=graph_id, - name=name, - description="MiroFish Social Simulation Graph" + + self._retry_zep_operation( + "create_graph", + lambda: self.client.graph.create( + graph_id=graph_id, + name=name, + description="MiroFish Social Simulation Graph" + ), + max_retries=max_retries, ) return graph_id - def set_ontology(self, graph_id: str, ontology: Dict[str, Any]): + def set_ontology(self, graph_id: str, ontology: Dict[str, Any], max_retries: Optional[int] = None): """设置图谱本体(公开方法)""" import warnings from typing import Optional @@ -279,10 +345,14 @@ def safe_attr_name(attr_name: str) -> str: # 调用Zep API设置本体 if entity_types or edge_definitions: - self.client.graph.set_ontology( - graph_ids=[graph_id], - entities=entity_types if entity_types else None, - edges=edge_definitions if edge_definitions else None, + self._retry_zep_operation( + "set_ontology", + lambda: self.client.graph.set_ontology( + graph_ids=[graph_id], + entities=entity_types if entity_types else None, + edges=edge_definitions if edge_definitions else None, + ), + max_retries=max_retries, ) def add_text_batches( @@ -314,27 +384,31 @@ def add_text_batches( for chunk in batch_chunks ] - # 发送到Zep - try: - batch_result = self.client.graph.add_batch( + def send_batch(): + return self.client.graph.add_batch( graph_id=graph_id, episodes=episodes ) - - # 收集返回的 episode uuid - if batch_result and isinstance(batch_result, list): - for ep in batch_result: - ep_uuid = getattr(ep, 'uuid_', None) or getattr(ep, 'uuid', None) - if ep_uuid: - episode_uuids.append(ep_uuid) - - # 避免请求过快 - time.sleep(1) - - except Exception as e: - if progress_callback: - progress_callback(f"批次 {batch_num} 发送失败: {str(e)}", 0) - raise + + batch_result = self._retry_zep_operation( + f"add_batch[{batch_num}]", + send_batch, + progress_callback=progress_callback, + progress_message=lambda attempt, total, wait_time: ( + f"批次 {batch_num} 发送失败,{wait_time:.0f}秒后重试 ({attempt}/{total})..." + ), + progress_value=(i + len(batch_chunks)) / total_chunks, + ) + + # 收集返回的 episode uuid + if batch_result and isinstance(batch_result, list): + for ep in batch_result: + ep_uuid = getattr(ep, 'uuid_', None) or getattr(ep, 'uuid', None) + if ep_uuid: + episode_uuids.append(ep_uuid) + + # 避免请求过快 + time.sleep(1) return episode_uuids @@ -497,4 +571,3 @@ def get_graph_data(self, graph_id: str) -> Dict[str, Any]: def delete_graph(self, graph_id: str): """删除图谱""" self.client.graph.delete(graph_id=graph_id) - diff --git a/backend/tests/test_graph_builder.py b/backend/tests/test_graph_builder.py new file mode 100644 index 00000000..0b245248 --- /dev/null +++ b/backend/tests/test_graph_builder.py @@ -0,0 +1,127 @@ +import importlib +import sys +from types import ModuleType, SimpleNamespace + +import pytest + + +@pytest.fixture +def graph_builder_module(monkeypatch): + zep_cloud = ModuleType("zep_cloud") + zep_cloud_client = ModuleType("zep_cloud.client") + zep_cloud_ontology = ModuleType("zep_cloud.external_clients.ontology") + + class FakeEpisodeData: + def __init__(self, data, type): + self.data = data + self.type = type + + class FakeEntityEdgeSourceTarget: + def __init__(self, source, target): + self.source = source + self.target = target + + class FakeInternalServerError(Exception): + pass + + class FakeZep: + def __init__(self, api_key): + self.api_key = api_key + + class FakeEntityModel: + pass + + class FakeEntityText: + pass + + class FakeEdgeModel: + pass + + zep_cloud.EpisodeData = FakeEpisodeData + zep_cloud.EntityEdgeSourceTarget = FakeEntityEdgeSourceTarget + zep_cloud.InternalServerError = FakeInternalServerError + zep_cloud_client.Zep = FakeZep + zep_cloud_ontology.EntityModel = FakeEntityModel + zep_cloud_ontology.EntityText = FakeEntityText + zep_cloud_ontology.EdgeModel = FakeEdgeModel + + monkeypatch.setitem(sys.modules, "zep_cloud", zep_cloud) + monkeypatch.setitem(sys.modules, "zep_cloud.client", zep_cloud_client) + monkeypatch.setitem(sys.modules, "zep_cloud.external_clients.ontology", zep_cloud_ontology) + monkeypatch.delitem(sys.modules, "app.services.graph_builder", raising=False) + + return importlib.import_module("app.services.graph_builder") + + +def build_service(graph_builder_module): + service = graph_builder_module.GraphBuilderService.__new__(graph_builder_module.GraphBuilderService) + service.client = SimpleNamespace(graph=SimpleNamespace()) + service.logger = SimpleNamespace(warning=lambda *args, **kwargs: None) + return service + + +def test_create_graph_retries_transient_zep_errors(graph_builder_module, monkeypatch): + service = build_service(graph_builder_module) + sleep_calls = [] + create_calls = [] + + def fake_create(**kwargs): + create_calls.append(kwargs) + if len(create_calls) < 3: + raise RuntimeError("429 Too Many Requests") + + service.client.graph.create = fake_create + monkeypatch.setattr(graph_builder_module.time, "sleep", sleep_calls.append) + + graph_id = service.create_graph("retry-test", max_retries=3) + + assert graph_id.startswith("mirofish_") + assert len(create_calls) == 3 + assert sleep_calls == [2.0, 4.0] + + +def test_create_graph_does_not_retry_non_transient_errors(graph_builder_module, monkeypatch): + service = build_service(graph_builder_module) + sleep_calls = [] + create_calls = [] + + def fake_create(**kwargs): + create_calls.append(kwargs) + raise ValueError("invalid graph payload") + + service.client.graph.create = fake_create + monkeypatch.setattr(graph_builder_module.time, "sleep", sleep_calls.append) + + with pytest.raises(ValueError, match="invalid graph payload"): + service.create_graph("no-retry", max_retries=3) + + assert len(create_calls) == 1 + assert sleep_calls == [] + + +def test_add_text_batches_retries_failed_batch_once(graph_builder_module, monkeypatch): + service = build_service(graph_builder_module) + sleep_calls = [] + progress_updates = [] + add_batch_calls = [] + + def fake_add_batch(**kwargs): + add_batch_calls.append(kwargs) + if len(add_batch_calls) == 1: + raise RuntimeError("503 Service Unavailable") + return [SimpleNamespace(uuid_="episode-1"), SimpleNamespace(uuid="episode-2")] + + service.client.graph.add_batch = fake_add_batch + monkeypatch.setattr(graph_builder_module.time, "sleep", sleep_calls.append) + + episode_ids = service.add_text_batches( + "graph-1", + ["chunk-a", "chunk-b"], + batch_size=2, + progress_callback=lambda message, progress: progress_updates.append((message, progress)), + ) + + assert episode_ids == ["episode-1", "episode-2"] + assert len(add_batch_calls) == 2 + assert sleep_calls == [2.0, 1] + assert any("重试" in message for message, _ in progress_updates) diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index f019b3fa..5b195340 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:44:20.498945+00:00", + "captured_at": "2026-03-11T06:45:56.886800+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index b7d8c2e9..63027743 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:44:20.499587+00:00` +- Captured: `2026-03-11T06:45:56.887499+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 95318686..077bab6e 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -18,19 +18,19 @@ Last refreshed: `2026-03-11` - `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. - `#127` Handle `None` response content: safe guard against provider edge cases. - `#129` Safe subset landed locally: configurable `LLM_MAX_TOKENS`, automatic retry after context-length failures, and report-agent message pruning to reduce overflow crashes. +- `#131` Safe subset landed locally: Zep graph creation, ontology setup, and batch uploads now retry only transient failures (429/timeout/5xx-style cases) with bounded backoff, plus targeted regression tests. - `#130` Add `CONTRIBUTING.md`: safe docs-only cherry-pick. - `#132` Add README architecture overview: safe docs-only cherry-pick. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. ## Deferred for later review -- `#131` Zep retry mechanism: relevant to rate-limit and transient-connectivity issues, but broader behavioral change than the already-landed fixes and should be validated with targeted backend tests first. - `#105` Security and error-handling sweep: high-value, but touches multiple API surfaces and config defaults, so it needs a dedicated pass instead of bundling into a low-risk cherry-pick cycle. ## Validation status - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. -- `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py -q` passes with targeted regression coverage for context-length retry and default token configuration. +- `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. - Follow-up is tracked in local beads issue `mirofish-ba6` to establish a lighter backend validation path. From 2541b6aac9f52c061ff8102348c07def425d68cd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:49:45 +0000 Subject: [PATCH 013/373] docs: add lightweight backend test path --- README-EN.md | 10 ++++++++++ README.md | 10 ++++++++++ docs/upstream-triage.md | 2 +- package.json | 3 ++- scripts/test_backend_lite.sh | 20 ++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100755 scripts/test_backend_lite.sh diff --git a/README-EN.md b/README-EN.md index faa6ba6d..9ecad2e6 100644 --- a/README-EN.md +++ b/README-EN.md @@ -274,6 +274,16 @@ npm run backend # Start backend only npm run frontend # Start frontend only ``` +#### 4. Lightweight Backend Validation + +If `uv sync` or `uv run pytest` is blocked by heavyweight builds such as `tiktoken` requiring a Rust toolchain, run the fast targeted backend suite instead: + +```bash +npm run test:backend:lite +``` + +This path creates `.tmp-test-venv/` on demand and installs only the packages needed for the current low-risk regression tests (`test_llm_client.py` and `test_graph_builder.py`). + ### Option 2: Docker Deployment ```bash diff --git a/README.md b/README.md index 66b17479..d9121ce7 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,16 @@ npm run backend # 仅启动后端 npm run frontend # 仅启动前端 ``` +#### 4. 轻量后端校验 + +如果 `uv sync` 或 `uv run pytest` 因 `tiktoken` 等重依赖需要 Rust 工具链而受阻,可先运行仓库内置的快速后端校验路径: + +```bash +npm run test:backend:lite +``` + +该路径会按需创建 `.tmp-test-venv/`,只安装当前低风险回归测试所需的最小依赖,并执行 `test_llm_client.py` 与 `test_graph_builder.py`。 + ### 二、Docker 部署 ```bash diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 077bab6e..1fd7f0e2 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -30,9 +30,9 @@ Last refreshed: `2026-03-11` - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. +- `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. -- Follow-up is tracked in local beads issue `mirofish-ba6` to establish a lighter backend validation path. ## Snapshot artifacts diff --git a/package.json b/package.json index 63ace21a..eff7fbf7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "dev": "concurrently --kill-others -n \"backend,frontend\" -c \"green,cyan\" \"npm run backend\" \"npm run frontend\"", "backend": "cd backend && uv run python run.py", "frontend": "cd frontend && npm run dev", - "build": "cd frontend && npm run build" + "build": "cd frontend && npm run build", + "test:backend:lite": "bash ./scripts/test_backend_lite.sh" }, "devDependencies": { "concurrently": "^9.1.2" diff --git a/scripts/test_backend_lite.sh b/scripts/test_backend_lite.sh new file mode 100755 index 00000000..2b96ed2c --- /dev/null +++ b/scripts/test_backend_lite.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +VENV_DIR="${ROOT_DIR}/.tmp-test-venv" + +if [ ! -d "${VENV_DIR}" ]; then + python3 -m venv "${VENV_DIR}" +fi + +# Keep the lightweight path limited to the dependencies needed by the fast unit tests. +"${VENV_DIR}/bin/pip" install -q \ + "pytest>=8.0.0" \ + "openai>=1.0.0" \ + "python-dotenv>=1.0.0" + +"${VENV_DIR}/bin/pytest" \ + "${ROOT_DIR}/backend/tests/test_llm_client.py" \ + "${ROOT_DIR}/backend/tests/test_graph_builder.py" \ + -q From 97af5e8af54bf7e643c20f92bfed023aeff23b23 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:52:03 +0000 Subject: [PATCH 014/373] fix: harden ontology validation and exception scope --- backend/app/api/simulation.py | 2 +- .../app/services/oasis_profile_generator.py | 3 +- backend/app/services/ontology_generator.py | 21 ++++- .../services/simulation_config_generator.py | 5 +- backend/tests/test_ontology_generator.py | 83 +++++++++++++++++++ docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 + 10 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 backend/tests/test_ontology_generator.py diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py index 3a0f6816..f2d3fd70 100644 --- a/backend/app/api/simulation.py +++ b/backend/app/api/simulation.py @@ -962,7 +962,7 @@ def get_simulation_history(): try: created_date = sim_dict.get("created_at", "")[:10] sim_dict["created_date"] = created_date - except: + except Exception: sim_dict["created_date"] = "" enriched_simulations.append(sim_dict) diff --git a/backend/app/services/oasis_profile_generator.py b/backend/app/services/oasis_profile_generator.py index 57836c53..19e56050 100644 --- a/backend/app/services/oasis_profile_generator.py +++ b/backend/app/services/oasis_profile_generator.py @@ -642,7 +642,7 @@ def fix_string_newlines(match): result = json.loads(json_str) result["_fixed"] = True return result - except: + except Exception: pass # 6. 尝试从内容中提取部分信息 @@ -1197,4 +1197,3 @@ def save_profiles_to_json( """[已废弃] 请使用 save_profiles() 方法""" logger.warning("save_profiles_to_json已废弃,请使用save_profiles方法") self.save_profiles(profiles, file_path, platform) - diff --git a/backend/app/services/ontology_generator.py b/backend/app/services/ontology_generator.py index 2d3e39bd..8d79623c 100644 --- a/backend/app/services/ontology_generator.py +++ b/backend/app/services/ontology_generator.py @@ -266,7 +266,15 @@ def _validate_and_process(self, result: Dict[str, Any]) -> Dict[str, Any]: result["analysis_summary"] = "" # 验证实体类型 + validated_entities = [] for entity in result["entity_types"]: + if isinstance(entity, str): + entity = { + "name": entity, + "description": f"Entity type: {entity}" + } + if not isinstance(entity, dict): + continue if "attributes" not in entity: entity["attributes"] = [] if "examples" not in entity: @@ -274,15 +282,27 @@ def _validate_and_process(self, result: Dict[str, Any]) -> Dict[str, Any]: # 确保description不超过100字符 if len(entity.get("description", "")) > 100: entity["description"] = entity["description"][:97] + "..." + validated_entities.append(entity) + result["entity_types"] = validated_entities # 验证关系类型 + validated_edges = [] for edge in result["edge_types"]: + if isinstance(edge, str): + edge = { + "name": edge, + "description": f"Relationship type: {edge}" + } + if not isinstance(edge, dict): + continue if "source_targets" not in edge: edge["source_targets"] = [] if "attributes" not in edge: edge["attributes"] = [] if len(edge.get("description", "")) > 100: edge["description"] = edge["description"][:97] + "..." + validated_edges.append(edge) + result["edge_types"] = validated_edges # Zep API 限制:最多 10 个自定义实体类型,最多 10 个自定义边类型 MAX_ENTITY_TYPES = 10 @@ -450,4 +470,3 @@ def generate_python_code(self, ontology: Dict[str, Any]) -> str: code_lines.append('}') return '\n'.join(code_lines) - diff --git a/backend/app/services/simulation_config_generator.py b/backend/app/services/simulation_config_generator.py index cc362508..90d0851b 100644 --- a/backend/app/services/simulation_config_generator.py +++ b/backend/app/services/simulation_config_generator.py @@ -520,13 +520,13 @@ def fix_string(match): try: return json.loads(json_str) - except: + except Exception: # 尝试移除所有控制字符 json_str = re.sub(r'[\x00-\x1f\x7f-\x9f]', ' ', json_str) json_str = re.sub(r'\s+', ' ', json_str) try: return json.loads(json_str) - except: + except Exception: pass return None @@ -984,4 +984,3 @@ def _generate_agent_config_by_rule(self, entity: EntityNode) -> Dict[str, Any]: "influence_weight": 1.0 } - diff --git a/backend/tests/test_ontology_generator.py b/backend/tests/test_ontology_generator.py new file mode 100644 index 00000000..e7c8bdb4 --- /dev/null +++ b/backend/tests/test_ontology_generator.py @@ -0,0 +1,83 @@ +import importlib.util +import sys +import types +from pathlib import Path + + +def load_ontology_generator(): + backend_root = Path(__file__).resolve().parents[1] + app_root = backend_root / "app" + services_root = app_root / "services" + module_path = services_root / "ontology_generator.py" + + app_module = sys.modules.setdefault("app", types.ModuleType("app")) + app_module.__path__ = [str(app_root)] + + services_module = sys.modules.setdefault("app.services", types.ModuleType("app.services")) + services_module.__path__ = [str(services_root)] + + spec = importlib.util.spec_from_file_location("app.services.ontology_generator", module_path) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +OntologyGenerator = load_ontology_generator().OntologyGenerator + + +def test_validate_and_process_normalizes_string_and_invalid_ontology_items(): + generator = OntologyGenerator(llm_client=object()) + + result = generator._validate_and_process( + { + "entity_types": [ + "PersonLike", + { + "name": "Analyst", + "description": "x" * 120, + }, + 123, + ], + "edge_types": [ + "RELATES_TO", + { + "name": "MENTIONS", + "description": "y" * 120, + }, + None, + ], + } + ) + + assert result["entity_types"][0] == { + "name": "PersonLike", + "description": "Entity type: PersonLike", + "attributes": [], + "examples": [], + } + assert result["entity_types"][1]["name"] == "Analyst" + assert result["entity_types"][1]["attributes"] == [] + assert result["entity_types"][1]["examples"] == [] + assert result["entity_types"][1]["description"].endswith("...") + assert len(result["entity_types"][1]["description"]) == 100 + assert {entity["name"] for entity in result["entity_types"]} >= { + "Person", + "Organization", + } + + assert result["edge_types"] == [ + { + "name": "RELATES_TO", + "description": "Relationship type: RELATES_TO", + "source_targets": [], + "attributes": [], + }, + { + "name": "MENTIONS", + "description": ("y" * 97) + "...", + "source_targets": [], + "attributes": [], + }, + ] diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 5b195340..c919696b 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:45:56.886800+00:00", + "captured_at": "2026-03-11T06:51:29.363685+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 63027743..38909a41 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:45:56.887499+00:00` +- Captured: `2026-03-11T06:51:29.364405+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 62f5d422..0fef4487 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:44:19.616630+00:00", + "captured_at": "2026-03-11T06:51:28.280283+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index bfdb9f78..0846def4 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T06:44:19.617195+00:00` +- Captured: `2026-03-11T06:51:28.280854+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 1fd7f0e2..458cbbbb 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -21,6 +21,8 @@ Last refreshed: `2026-03-11` - `#131` Safe subset landed locally: Zep graph creation, ontology setup, and batch uploads now retry only transient failures (429/timeout/5xx-style cases) with bounded backoff, plus targeted regression tests. - `#130` Add `CONTRIBUTING.md`: safe docs-only cherry-pick. - `#132` Add README architecture overview: safe docs-only cherry-pick. +- `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. +- `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. ## Deferred for later review @@ -32,6 +34,7 @@ Last refreshed: `2026-03-11` - `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. +- `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. ## Snapshot artifacts From 2b23ba0f79122f1259177d8939c22e699ab0cd11 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:54:45 +0000 Subject: [PATCH 015/373] fix: make vite proxy target configurable --- .env.example | 6 +++++- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 6 ++++-- frontend/vite.config.js | 27 ++++++++++++++++----------- 7 files changed, 29 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index 576afe90..e1984b52 100644 --- a/.env.example +++ b/.env.example @@ -19,6 +19,10 @@ LLM_BOOST_API_KEY=your_api_key_here LLM_BOOST_BASE_URL=your_base_url_here LLM_BOOST_MODEL_NAME=your_model_name_here -# ===== 前端 API 超时配置(可选)===== +# ===== 前端配置(可选)===== +# 开发模式前端代理到的后端地址,默认 http://localhost:5001 +# 如果后端运行在其他主机或端口,请设置 VITE_API_BASE_URL +# VITE_API_BASE_URL=http://localhost:5001 + # 本地大模型响应较慢时可以增加此值(毫秒) # VITE_API_TIMEOUT=600000 diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index c919696b..3d82f657 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:51:29.363685+00:00", + "captured_at": "2026-03-11T06:53:05.278728+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 38909a41..d64a272d 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:51:29.364405+00:00` +- Captured: `2026-03-11T06:53:05.279463+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 0fef4487..bd4d435d 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:51:28.280283+00:00", + "captured_at": "2026-03-11T06:53:04.467663+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 0846def4..100ace12 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T06:51:28.280854+00:00` +- Captured: `2026-03-11T06:53:04.468245+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 458cbbbb..aa29dba2 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -6,11 +6,12 @@ Last refreshed: `2026-03-11` - Keep reusable local snapshots of `666ghj/MiroFish` open and full issue/PR state. - Land small, low-risk upstream fixes before considering larger feature branches. -- Make backend compatibility with OpenAI-compatible providers explicit in code and docs. +- Keep OpenAI-compatible backend support verified in both code paths and docs while reviewing the remaining open PR queue. ## Landed on this branch - `#81` Configurable frontend API timeout: low-risk support for slow local/OpenAI-compatible backends such as Ollama. +- `#104` Make Vite dev proxy target configurable with `VITE_API_BASE_URL`: removes another hardcoded localhost assumption for custom backend hosts and ports. - `#115` Use SPDX license string: safe metadata-only cherry-pick. - `#116` Upgrade GitHub Actions: safe workflow-only dependency bump. - `#125` Improve new-project network error diagnostics: safe single-file frontend error-message improvement. @@ -24,6 +25,7 @@ Last refreshed: `2026-03-11` - `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. +- Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. ## Deferred for later review @@ -31,7 +33,7 @@ Last refreshed: `2026-03-11` ## Validation status - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. -- `cd frontend && npm run build` passes after landing `#129` subset and the OpenAI-alias compatibility updates. +- `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 7cec1a71..0c89d7ee 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,17 +1,22 @@ -import { defineConfig } from 'vite' +import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' // https://vite.dev/config/ -export default defineConfig({ - plugins: [vue()], - server: { - port: 3000, - open: true, - proxy: { - '/api': { - target: 'http://localhost:5001', - changeOrigin: true, - secure: false +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), '') + const apiBaseUrl = env.VITE_API_BASE_URL || 'http://localhost:5001' + + return { + plugins: [vue()], + server: { + port: 3000, + open: true, + proxy: { + '/api': { + target: apiBaseUrl, + changeOrigin: true, + secure: false + } } } } From 94f3bd0231bb75b8f28540e5e3aeb7efa03d21dd Mon Sep 17 00:00:00 2001 From: Kim taek seo Date: Tue, 10 Mar 2026 14:19:36 +0900 Subject: [PATCH 016/373] korean readme (cherry picked from commit 9817c535d77dbd69ccefa58ca96cbae497dbff47) --- README-EN.md | 2 +- README-KO.md | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 +- 3 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 README-KO.md diff --git a/README-EN.md b/README-EN.md index 9ecad2e6..8bb2e525 100644 --- a/README-EN.md +++ b/README-EN.md @@ -20,7 +20,7 @@ [![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) [![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) -[English](./README-EN.md) | [中文文档](./README.md) +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) diff --git a/README-KO.md b/README-KO.md new file mode 100644 index 00000000..ebf2058c --- /dev/null +++ b/README-KO.md @@ -0,0 +1,205 @@ +
+ +MiroFish Logo + +666ghj%2FMiroFish | Trendshift + +간결하고 범용적인 군집 지능 엔진, 무엇이든 예측합니다 +
+A Simple and Universal Swarm Intelligence Engine, Predicting Anything + +666ghj%2MiroFish | Shanda + +[![GitHub Stars](https://img.shields.io/github/stars/666ghj/MiroFish?style=flat-square&color=DAA520)](https://github.com/666ghj/MiroFish/stargazers) +[![GitHub Watchers](https://img.shields.io/github/watchers/666ghj/MiroFish?style=flat-square)](https://github.com/666ghj/MiroFish/watchers) +[![GitHub Forks](https://img.shields.io/github/forks/666ghj/MiroFish?style=flat-square)](https://github.com/666ghj/MiroFish/network) +[![Docker](https://img.shields.io/badge/Docker-Build-2496ED?style=flat-square&logo=docker&logoColor=white)](https://hub.docker.com/) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/666ghj/MiroFish) + +[![Discord](https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.com/channels/1469200078932545606/1469201282077163739) +[![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) +[![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) + +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README.md) + +
+ +## ⚡ 프로젝트 개요 + +**MiroFish**는 멀티 에이전트 기술 기반의 차세대 AI 예측 엔진입니다. 현실 세계의 시드 정보(속보, 정책 초안, 금융 신호 등)를 추출해 고충실도의 평행 디지털 세계를 자동으로 구성합니다. 이 공간 안에서 독립적인 성격, 장기 기억, 행동 로직을 가진 수많은 지능형 에이전트가 자유롭게 상호작용하며 사회적으로 진화합니다. 사용자는 "신의 시점"에서 변수를 동적으로 주입해 미래의 전개를 정밀하게 시뮬레이션할 수 있습니다. 즉, **디지털 샌드박스에서 미래를 미리 리허설하고, 수많은 시뮬레이션을 거쳐 더 나은 결정을 내릴 수 있게 해줍니다.** + +> 당신이 할 일은 간단합니다: 시드 자료(데이터 분석 보고서나 흥미로운 소설 이야기)를 업로드하고 자연어로 예측 요구를 설명하세요.
+> MiroFish는 다음을 반환합니다: 자세한 예측 보고서와 깊이 상호작용할 수 있는 고충실도 디지털 세계 + +### 우리의 비전 + +MiroFish는 현실을 비추는 군집 지능의 거울을 만드는 것을 목표로 합니다. 개별 상호작용이 만들어내는 집단적 창발을 포착해 기존 예측 방식의 한계를 넘어섭니다. + +- **거시적 관점**: 정책과 홍보 전략을 무위험 환경에서 시험할 수 있는 의사결정자용 리허설 실험실 +- **미시적 관점**: 소설 결말을 추론하거나 상상력을 실험하는 등 누구나 재미있고 쉽게 활용할 수 있는 개인용 창작 샌드박스 + +진지한 예측부터 흥미로운 시뮬레이션까지, MiroFish는 모든 "만약"에 대한 결과를 먼저 보여주며 무엇이든 예측할 수 있는 가능성을 열어 줍니다. + +## 🌐 온라인 데모 + +온라인 데모 환경에서 준비된 화제성 여론 사건 예측 시뮬레이션을 직접 체험해 보세요: [mirofish-live-demo](https://666ghj.github.io/mirofish-demo/) + +## 📸 시스템 스크린샷 + +
+ + + + + + + + + + + + + +
스크린샷 1스크린샷 2
스크린샷 3스크린샷 4
스크린샷 5스크린샷 6
+
+ +## 🎬 데모 영상 + +### 1. 우한대학교 여론 시뮬레이션 예측 + MiroFish 프로젝트 소개 + +
+MiroFish Demo Video + +이미지를 클릭하면 BettaFish가 생성한 "우한대학교 여론 보고서"를 기반으로 예측을 수행하는 전체 데모 영상을 볼 수 있습니다. +
+ +### 2. 《홍루몽》 유실 결말 예측 시뮬레이션 + +
+MiroFish Demo Video + +이미지를 클릭하면 《홍루몽》 앞 80회 분량의 방대한 텍스트를 바탕으로 MiroFish가 유실 결말을 심층 예측하는 영상을 볼 수 있습니다. +
+ +> **금융 예측**, **정치/시사 뉴스 예측** 등 더 많은 예제가 계속 추가될 예정입니다. + +## 🔄 워크플로우 + +1. **그래프 구축**: 현실 시드 추출 · 개인/집단 기억 주입 · GraphRAG 구축 +2. **환경 구성**: 엔터티 관계 추출 · 페르소나 생성 · 환경 설정 에이전트의 시뮬레이션 파라미터 주입 +3. **시뮬레이션 시작**: 양대 플랫폼 병렬 시뮬레이션 · 예측 요구 자동 해석 · 시간 기반 기억 동적 갱신 +4. **보고서 생성**: ReportAgent가 풍부한 도구 세트로 시뮬레이션 이후 환경과 깊이 상호작용 +5. **심층 인터랙션**: 시뮬레이션 세계 속 개체 또는 ReportAgent와 대화 + +## 🚀 빠른 시작 + +### 1. 소스코드 배포 (권장) + +#### 사전 요구사항 + +| 도구 | 버전 요구사항 | 설명 | 설치 확인 | +|------|--------------|------|-----------| +| **Node.js** | 18+ | 프런트엔드 실행 환경, npm 포함 | `node -v` | +| **Python** | ≥3.11, ≤3.12 | 백엔드 실행 환경 | `python --version` | +| **uv** | 최신 버전 | Python 패키지 관리자 | `uv --version` | + +#### 1) 환경 변수 설정 + +```bash +# 예시 설정 파일 복사 +cp .env.example .env + +# .env 파일을 열어 필요한 API 키 입력 +``` + +**필수 환경 변수** + +```env +# LLM API 설정 (OpenAI SDK 형식을 지원하는 모든 LLM API 사용 가능) +# 권장: 알리바바 Bailian Platform의 qwen-plus 모델 +# https://bailian.console.aliyun.com/ +# 비용 소모가 클 수 있으므로 처음에는 40라운드 미만으로 테스트를 권장합니다. +LLM_API_KEY=your_api_key +LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 +LLM_MODEL_NAME=qwen-plus + +# Zep Cloud 설정 +# 간단한 사용에는 월간 무료 할당량으로 충분합니다. +# https://app.getzep.com/ +ZEP_API_KEY=your_zep_api_key +``` + +#### 2) 의존성 설치 + +```bash +# 모든 의존성 한 번에 설치 (루트 + 프런트엔드 + 백엔드) +npm run setup:all +``` + +또는 단계별 설치: + +```bash +# Node 의존성 설치 (루트 + 프런트엔드) +npm run setup + +# Python 의존성 설치 (백엔드, 가상환경 자동 생성) +npm run setup:backend +``` + +#### 3) 서비스 실행 + +```bash +# 프런트엔드와 백엔드를 동시에 실행 (프로젝트 루트에서 실행) +npm run dev +``` + +**서비스 주소** +- 프런트엔드: `http://localhost:3000` +- 백엔드 API: `http://localhost:5001` + +**개별 실행** + +```bash +npm run backend # 백엔드만 실행 +npm run frontend # 프런트엔드만 실행 +``` + +### 2. Docker 배포 + +```bash +# 1. 환경 변수 설정 (소스코드 배포와 동일) +cp .env.example .env + +# 2. 이미지 가져오기 및 실행 +docker compose up -d +``` + +기본적으로 루트 디렉터리의 `.env`를 읽고 `3000(프런트엔드) / 5001(백엔드)` 포트를 매핑합니다. + +> 더 빠른 이미지 풀링을 위한 미러 주소가 `docker-compose.yml` 주석에 포함되어 있으니 필요에 맞게 바꿔 사용할 수 있습니다. + +## 📬 커뮤니티 및 문의 + +
+커뮤니티 그룹 +
+ +  + +MiroFish 팀은 상시로 정규직/인턴을 모집하고 있습니다. 멀티 에이전트 애플리케이션에 관심이 있다면 아래 메일로 이력서를 보내 주세요: **mirofish@shanda.com** + +## 📄 감사의 말 + +**MiroFish는 Shanda Group의 전략적 지원과 인큐베이팅을 받고 있습니다!** + +MiroFish의 시뮬레이션 엔진은 **[OASIS](https://github.com/camel-ai/oasis)** 기반으로 동작합니다. CAMEL-AI 팀의 오픈소스 기여에 깊이 감사드립니다. + +## 📈 프로젝트 통계 + + + + + + Star History Chart + + diff --git a/README.md b/README.md index d9121ce7..cb06c0a8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ [![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) [![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) -[English](./README-EN.md) | [中文文档](./README.md) +[English](./README-EN.md) | [中文文档](./README.md) | [中文文档](./README-KO.md) From cec7a15c19ad8cc27a3ac2c4103a634bcb85315b Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Tue, 10 Mar 2026 15:38:00 +0900 Subject: [PATCH 017/373] docs(readme): add Japanese README (cherry picked from commit 0531fa640d186bf27de03c01d4bcc4bcd315cf4d) --- README-EN.md | 6 +- README-JA.md | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++ README-KO.md | 2 +- README.md | 6 +- 4 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 README-JA.md diff --git a/README-EN.md b/README-EN.md index 8bb2e525..e601c5fd 100644 --- a/README-EN.md +++ b/README-EN.md @@ -20,7 +20,11 @@ [![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) [![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) -[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) +<<<<<<< HEAD +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) | [日本語](./README-JA.md) +======= +[English](./README-EN.md) | [中文文档](./README.md) | [日本語](./README-JA.md) +>>>>>>> 0531fa6 (docs(readme): add Japanese README) diff --git a/README-JA.md b/README-JA.md new file mode 100644 index 00000000..49991f14 --- /dev/null +++ b/README-JA.md @@ -0,0 +1,203 @@ +
+ +MiroFish Logo + +666ghj%2FMiroFish | Trendshift + +シンプルで汎用的な群知能エンジン、あらゆるものを予測 +
+A Simple and Universal Swarm Intelligence Engine, Predicting Anything + +666ghj%2MiroFish | Shanda + +[![GitHub Stars](https://img.shields.io/github/stars/666ghj/MiroFish?style=flat-square&color=DAA520)](https://github.com/666ghj/MiroFish/stargazers) +[![GitHub Watchers](https://img.shields.io/github/watchers/666ghj/MiroFish?style=flat-square)](https://github.com/666ghj/MiroFish/watchers) +[![GitHub Forks](https://img.shields.io/github/forks/666ghj/MiroFish?style=flat-square)](https://github.com/666ghj/MiroFish/network) +[![Docker](https://img.shields.io/badge/Docker-Build-2496ED?style=flat-square&logo=docker&logoColor=white)](https://hub.docker.com/) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/666ghj/MiroFish) + +[![Discord](https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.com/channels/1469200078932545606/1469201282077163739) +[![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) +[![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) + +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) | [日本語](./README-JA.md) + +
+ +## ⚡ 概要 + +**MiroFish** は、マルチエージェント技術を活用した次世代AI予測エンジンです。現実世界からシード情報(ニュース速報、政策草案、金融シグナルなど)を抽出し、高精度なパラレルデジタルワールドを自動構築します。この空間内で、独自の性格・長期記憶・行動ロジックを持つ数千のインテリジェントエージェントが自由に相互作用し、社会的進化を遂げます。「神の視点」から動的に変数を注入することで、未来の軌跡を精密に推論できます — **デジタルサンドボックスで未来をリハーサルし、無数のシミュレーションを経て最適な意思決定を導き出します**。 + +> 必要な操作は:シード素材(データ分析レポートや興味深い小説など)をアップロードし、予測要件を自然言語で記述するだけ
+> MiroFish が返すもの:詳細な予測レポートと、深くインタラクティブな高精度デジタルワールド + +### 私たちのビジョン + +MiroFish は、現実を映し出す群知能ミラーの構築を目指しています。個体間の相互作用から生まれる集合的創発を捉えることで、従来の予測の限界を突破します: + +- **マクロレベル**:意思決定者のためのリハーサルラボとして、政策や広報をゼロリスクで検証可能 +- **ミクロレベル**:個人ユーザーのためのクリエイティブサンドボックス — 小説の結末推理から想像力豊かなシナリオの探索まで、すべてを楽しく、遊び心を持って体験可能 + +シリアスな予測から遊び心あるシミュレーションまで、あらゆる「もしも」の結果を可視化し、万物の予測を可能にします。 + +## 🌐 ライブデモ + +オンラインデモ環境をぜひご覧ください。トレンドの世論イベントに関する予測シミュレーションを体験できます:[mirofish-live-demo](https://666ghj.github.io/mirofish-demo/) + +## 📸 スクリーンショット + +
+ + + + + + + + + + + + + +
スクリーンショット 1スクリーンショット 2
スクリーンショット 3スクリーンショット 4
スクリーンショット 5スクリーンショット 6
+
+ +## 🎬 デモ動画 + +### 1. 武漢大学世論シミュレーション + MiroFish プロジェクト紹介 + +
+MiroFish デモ動画 + +画像をクリックして、BettaFish生成の「武漢大学世論レポート」を使用した予測の完全デモ動画をご覧ください +
+ +### 2. 紅楼夢 失われた結末シミュレーション + +
+MiroFish デモ動画 + +画像をクリックして、「紅楼夢」前80回の数十万字に基づくMiroFishの失われた結末の深層予測をご覧ください +
+ +> **金融予測**、**政治ニュース予測** などの事例を近日公開予定... + +## 🔄 ワークフロー + +1. **グラフ構築**:シード抽出 & 個体/集合記憶の注入 & GraphRAG構築 +2. **環境セットアップ**:エンティティ関係抽出 & ペルソナ生成 & エージェント設定注入 +3. **シミュレーション**:デュアルプラットフォーム並列シミュレーション & 予測要件の自動解析 & 動的時間記憶更新 +4. **レポート生成**:豊富なツールセットを持つReportAgentによるシミュレーション後環境との深いインタラクション +5. **深層インタラクション**:シミュレーション世界の任意のエージェントとチャット & ReportAgentとの対話 + +## 🚀 クイックスタート + +### オプション1:ソースコードデプロイ(推奨) + +#### 前提条件 + +| ツール | バージョン | 説明 | インストール確認 | +|------|---------|-------------|-------------------| +| **Node.js** | 18+ | フロントエンドランタイム、npm含む | `node -v` | +| **Python** | ≥3.11, ≤3.12 | バックエンドランタイム | `python --version` | +| **uv** | 最新版 | Pythonパッケージマネージャー | `uv --version` | + +#### 1. 環境変数の設定 + +```bash +# サンプル設定ファイルをコピー +cp .env.example .env + +# .envファイルを編集し、必要なAPIキーを入力 +``` + +**必須環境変数:** + +```env +# LLM API設定(OpenAI SDK形式の任意のLLM APIに対応) +# 推奨:阿里雲百錬プラットフォーム経由のQwen-plusモデル: https://bailian.console.aliyun.com/ +# 消費量が多いため、まず40ラウンド未満のシミュレーションをお試しください +LLM_API_KEY=your_api_key +LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 +LLM_MODEL_NAME=qwen-plus + +# Zep Cloud設定 +# 無料の月間クォータで簡単な利用には十分です: https://app.getzep.com/ +ZEP_API_KEY=your_zep_api_key +``` + +#### 2. 依存関係のインストール + +```bash +# すべての依存関係をワンクリックでインストール(ルート + フロントエンド + バックエンド) +npm run setup:all +``` + +または段階的にインストール: + +```bash +# Node依存関係をインストール(ルート + フロントエンド) +npm run setup + +# Python依存関係をインストール(バックエンド、仮想環境を自動作成) +npm run setup:backend +``` + +#### 3. サービスの起動 + +```bash +# フロントエンドとバックエンドを同時に起動(プロジェクトルートから実行) +npm run dev +``` + +**サービスURL:** +- フロントエンド: `http://localhost:3000` +- バックエンド API: `http://localhost:5001` + +**個別に起動:** + +```bash +npm run backend # バックエンドのみ起動 +npm run frontend # フロントエンドのみ起動 +``` + +### オプション2:Dockerデプロイ + +```bash +# 1. 環境変数を設定(ソースデプロイと同様) +cp .env.example .env + +# 2. イメージをプルして起動 +docker compose up -d +``` + +デフォルトでルートディレクトリの `.env` を読み取り、ポート `3000(フロントエンド)/ 5001(バックエンド)` をマッピング + +> 高速プル用のミラーアドレスが `docker-compose.yml` にコメントとして記載されています。必要に応じて差し替えてください。 + +## 📬 コミュニティに参加 + +
+QQグループ +
+ +  + +MiroFishチームはフルタイム/インターンシップのポジションを募集しています。マルチエージェントシミュレーションやLLMアプリケーションに興味がある方は、お気軽に履歴書をお送りください:**mirofish@shanda.com** + +## 📄 謝辞 + +**MiroFishは盛大グループから戦略的支援とインキュベーションを受けています!** + +MiroFishのシミュレーションエンジンは **[OASIS (Open Agent Social Interaction Simulations)](https://github.com/camel-ai/oasis)** を基盤としています。CAMEL-AIチームのオープンソース貢献に心より感謝いたします! + +## 📈 プロジェクト統計 + + + + + + Star History Chart + + diff --git a/README-KO.md b/README-KO.md index ebf2058c..ed612966 100644 --- a/README-KO.md +++ b/README-KO.md @@ -20,7 +20,7 @@ [![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) [![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) -[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README.md) +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) | [日本語](./README-JA.md) diff --git a/README.md b/README.md index cb06c0a8..edc6121b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,11 @@ [![X](https://img.shields.io/badge/X-Follow-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/mirofish_ai) [![Instagram](https://img.shields.io/badge/Instagram-Follow-E4405F?style=flat-square&logo=instagram&logoColor=white)](https://www.instagram.com/mirofish_ai/) -[English](./README-EN.md) | [中文文档](./README.md) | [中文文档](./README-KO.md) +<<<<<<< HEAD +[English](./README-EN.md) | [中文文档](./README.md) | [한국어](./README-KO.md) | [日本語](./README-JA.md) +======= +[English](./README-EN.md) | [中文文档](./README.md) | [日本語](./README-JA.md) +>>>>>>> 0531fa6 (docs(readme): add Japanese README) From 8197ec572fb25109d374a0ab017f018ae4f09864 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 06:57:06 +0000 Subject: [PATCH 018/373] docs: refresh upstream triage snapshot --- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 3d82f657..40a89a35 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:53:05.278728+00:00", + "captured_at": "2026-03-11T06:55:28.632940+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index d64a272d..8a0e6add 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:53:05.279463+00:00` +- Captured: `2026-03-11T06:55:28.633654+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index bd4d435d..2550812b 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:53:04.467663+00:00", + "captured_at": "2026-03-11T06:55:27.763557+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 100ace12..caffa1d9 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T06:53:04.468245+00:00` +- Captured: `2026-03-11T06:55:27.764126+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index aa29dba2..f48046ef 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -22,10 +22,13 @@ Last refreshed: `2026-03-11` - `#131` Safe subset landed locally: Zep graph creation, ontology setup, and batch uploads now retry only transient failures (429/timeout/5xx-style cases) with bounded backoff, plus targeted regression tests. - `#130` Add `CONTRIBUTING.md`: safe docs-only cherry-pick. - `#132` Add README architecture overview: safe docs-only cherry-pick. +- `#112` Add Korean README: safe docs-only cherry-pick; normalized cross-links with the other language READMEs while landing it locally. +- `#113` Add Japanese README: safe docs-only cherry-pick; normalized cross-links with the other language READMEs while landing it locally. - `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. +- `#114` Fix API base URL fallback is already superseded locally by the current frontend API client, which now falls back to the runtime origin and also supports `VITE_API_TIMEOUT`. ## Deferred for later review From d44fc45eb73a040c70c473e92bb110c4b7c7f75e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:02:07 +0000 Subject: [PATCH 019/373] fix: harden backend api error responses --- backend/app/api/graph.py | 27 +--- backend/app/api/report.py | 121 +++------------- backend/app/api/simulation.py | 211 ++++------------------------ backend/app/utils/__init__.py | 4 +- backend/app/utils/error_handler.py | 47 +++++++ backend/app/utils/file_parser.py | 12 +- backend/tests/test_error_handler.py | 66 +++++++++ docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 4 +- 12 files changed, 184 insertions(+), 316 deletions(-) create mode 100644 backend/app/utils/error_handler.py create mode 100644 backend/tests/test_error_handler.py diff --git a/backend/app/api/graph.py b/backend/app/api/graph.py index 12ff1ba2..d8fe4ff0 100644 --- a/backend/app/api/graph.py +++ b/backend/app/api/graph.py @@ -14,6 +14,7 @@ from ..services.graph_builder import GraphBuilderService from ..services.text_processor import TextProcessor from ..utils.file_parser import FileParser +from ..utils.error_handler import handle_api_exception from ..utils.logger import get_logger from ..models.task import TaskManager, TaskStatus from ..models.project import ProjectManager, ProjectStatus @@ -247,11 +248,7 @@ def generate_ontology(): }) except Exception as e: - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "生成本体失败") # ============== 接口2:构建图谱 ============== @@ -500,7 +497,7 @@ def wait_progress_callback(msg, progress_ratio): task_id, status=TaskStatus.FAILED, message=f"构建失败: {str(e)}", - error=traceback.format_exc() + error=traceback.format_exc() if Config.DEBUG else str(e) ) # 启动后台线程 @@ -517,11 +514,7 @@ def wait_progress_callback(msg, progress_ratio): }) except Exception as e: - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "启动图谱构建失败") # ============== 任务查询接口 ============== @@ -582,11 +575,7 @@ def get_graph_data(graph_id: str): }) except Exception as e: - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取图谱数据失败") @graph_bp.route('/delete/', methods=['DELETE']) @@ -610,8 +599,4 @@ def delete_graph(graph_id: str): }) except Exception as e: - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "删除图谱失败") diff --git a/backend/app/api/report.py b/backend/app/api/report.py index e05c73c3..0e893b67 100644 --- a/backend/app/api/report.py +++ b/backend/app/api/report.py @@ -4,7 +4,6 @@ """ import os -import traceback import threading from flask import request, jsonify, send_file @@ -14,6 +13,7 @@ from ..services.simulation_manager import SimulationManager from ..models.project import ProjectManager from ..models.task import TaskManager, TaskStatus +from ..utils.error_handler import handle_api_exception from ..utils.logger import get_logger logger = get_logger('mirofish.api.report') @@ -187,12 +187,7 @@ def progress_callback(stage, progress, message): }) except Exception as e: - logger.error(f"启动报告生成任务失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "启动报告生成任务失败") @report_bp.route('/generate/status', methods=['POST']) @@ -303,12 +298,7 @@ def get_report(report_id: str): }) except Exception as e: - logger.error(f"获取报告失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取报告失败") @report_bp.route('/by-simulation/', methods=['GET']) @@ -342,12 +332,7 @@ def get_report_by_simulation(simulation_id: str): }) except Exception as e: - logger.error(f"获取报告失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取报告失败") @report_bp.route('/list', methods=['GET']) @@ -382,12 +367,7 @@ def list_reports(): }) except Exception as e: - logger.error(f"列出报告失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "列出报告失败") @report_bp.route('//download', methods=['GET']) @@ -428,12 +408,7 @@ def download_report(report_id: str): ) except Exception as e: - logger.error(f"下载报告失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "下载报告失败") @report_bp.route('/', methods=['DELETE']) @@ -454,12 +429,7 @@ def delete_report(report_id: str): }) except Exception as e: - logger.error(f"删除报告失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "删除报告失败") # ============== Report Agent对话接口 ============== @@ -551,12 +521,7 @@ def chat_with_report_agent(): }) except Exception as e: - logger.error(f"对话失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "对话失败") # ============== 报告进度与分章节接口 ============== @@ -594,12 +559,7 @@ def get_report_progress(report_id: str): }) except Exception as e: - logger.error(f"获取报告进度失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取报告进度失败") @report_bp.route('//sections', methods=['GET']) @@ -645,12 +605,7 @@ def get_report_sections(report_id: str): }) except Exception as e: - logger.error(f"获取章节列表失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取章节列表失败") @report_bp.route('//section/', methods=['GET']) @@ -689,12 +644,7 @@ def get_single_section(report_id: str, section_index: int): }) except Exception as e: - logger.error(f"获取章节内容失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取章节内容失败") # ============== 报告状态检查接口 ============== @@ -740,12 +690,7 @@ def check_report_status(simulation_id: str): }) except Exception as e: - logger.error(f"检查报告状态失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "检查报告状态失败") # ============== Agent 日志接口 ============== @@ -801,12 +746,7 @@ def get_agent_log(report_id: str): }) except Exception as e: - logger.error(f"获取Agent日志失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取Agent日志失败") @report_bp.route('//agent-log/stream', methods=['GET']) @@ -835,12 +775,7 @@ def stream_agent_log(report_id: str): }) except Exception as e: - logger.error(f"获取Agent日志失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取Agent日志失败") # ============== 控制台日志接口 ============== @@ -883,12 +818,7 @@ def get_console_log(report_id: str): }) except Exception as e: - logger.error(f"获取控制台日志失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取控制台日志失败") @report_bp.route('//console-log/stream', methods=['GET']) @@ -917,12 +847,7 @@ def stream_console_log(report_id: str): }) except Exception as e: - logger.error(f"获取控制台日志失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取控制台日志失败") # ============== 工具调用接口(供调试使用)============== @@ -967,12 +892,7 @@ def search_graph_tool(): }) except Exception as e: - logger.error(f"图谱搜索失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "图谱搜索失败") @report_bp.route('/tools/statistics', methods=['POST']) @@ -1007,9 +927,4 @@ def get_graph_statistics_tool(): }) except Exception as e: - logger.error(f"获取图谱统计失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取图谱统计失败") diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py index f2d3fd70..a33e8c45 100644 --- a/backend/app/api/simulation.py +++ b/backend/app/api/simulation.py @@ -13,6 +13,7 @@ from ..services.oasis_profile_generator import OasisProfileGenerator from ..services.simulation_manager import SimulationManager, SimulationStatus from ..services.simulation_runner import SimulationRunner, RunnerStatus +from ..utils.error_handler import handle_api_exception from ..utils.logger import get_logger from ..models.project import ProjectManager @@ -81,12 +82,7 @@ def get_graph_entities(graph_id: str): }) except Exception as e: - logger.error(f"获取图谱实体失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取图谱实体失败") @simulation_bp.route('/entities//', methods=['GET']) @@ -114,12 +110,7 @@ def get_entity_detail(graph_id: str, entity_uuid: str): }) except Exception as e: - logger.error(f"获取实体详情失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取实体详情失败") @simulation_bp.route('/entities//by-type/', methods=['GET']) @@ -151,12 +142,7 @@ def get_entities_by_type(graph_id: str, entity_type: str): }) except Exception as e: - logger.error(f"获取实体失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取实体失败") # ============== 模拟管理接口 ============== @@ -228,12 +214,7 @@ def create_simulation(): }) except Exception as e: - logger.error(f"创建模拟失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "创建模拟失败") def _check_simulation_prepared(simulation_id: str) -> tuple: @@ -626,12 +607,7 @@ def progress_callback(stage, progress, message, **kwargs): }), 404 except Exception as e: - logger.error(f"启动准备任务失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "启动准备任务失败") @simulation_bp.route('/prepare/status', methods=['POST']) @@ -772,12 +748,7 @@ def get_simulation(simulation_id: str): }) except Exception as e: - logger.error(f"获取模拟状态失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取模拟状态失败") @simulation_bp.route('/list', methods=['GET']) @@ -801,12 +772,7 @@ def list_simulations(): }) except Exception as e: - logger.error(f"列出模拟失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "列出模拟失败") def _get_report_id_for_simulation(simulation_id: str) -> str: @@ -974,12 +940,7 @@ def get_simulation_history(): }) except Exception as e: - logger.error(f"获取历史模拟失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取历史模拟失败") @simulation_bp.route('//profiles', methods=['GET']) @@ -1012,12 +973,7 @@ def get_simulation_profiles(simulation_id: str): }), 404 except Exception as e: - logger.error(f"获取Profile失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取Profile失败") @simulation_bp.route('//profiles/realtime', methods=['GET']) @@ -1122,12 +1078,7 @@ def get_simulation_profiles_realtime(simulation_id: str): }) except Exception as e: - logger.error(f"实时获取Profile失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "实时获取Profile失败") @simulation_bp.route('//config/realtime', methods=['GET']) @@ -1242,12 +1193,7 @@ def get_simulation_config_realtime(simulation_id: str): }) except Exception as e: - logger.error(f"实时获取Config失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "实时获取Config失败") @simulation_bp.route('//config', methods=['GET']) @@ -1278,12 +1224,7 @@ def get_simulation_config(simulation_id: str): }) except Exception as e: - logger.error(f"获取配置失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取配置失败") @simulation_bp.route('//config/download', methods=['GET']) @@ -1307,12 +1248,7 @@ def download_simulation_config(simulation_id: str): ) except Exception as e: - logger.error(f"下载配置失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "下载配置失败") @simulation_bp.route('/script//download', methods=['GET']) @@ -1359,12 +1295,7 @@ def download_simulation_script(script_name: str): ) except Exception as e: - logger.error(f"下载脚本失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "下载脚本失败") # ============== Profile生成接口(独立使用) ============== @@ -1433,12 +1364,7 @@ def generate_profiles(): }) except Exception as e: - logger.error(f"生成Profile失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "生成Profile失败") # ============== 模拟运行控制接口 ============== @@ -1628,12 +1554,7 @@ def start_simulation(): }), 400 except Exception as e: - logger.error(f"启动模拟失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "启动模拟失败") @simulation_bp.route('/stop', methods=['POST']) @@ -1687,12 +1608,7 @@ def stop_simulation(): }), 400 except Exception as e: - logger.error(f"停止模拟失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "停止模拟失败") # ============== 实时状态监控接口 ============== @@ -1747,12 +1663,7 @@ def get_run_status(simulation_id: str): }) except Exception as e: - logger.error(f"获取运行状态失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取运行状态失败") @simulation_bp.route('//run-status/detail', methods=['GET']) @@ -1848,12 +1759,7 @@ def get_run_status_detail(simulation_id: str): }) except Exception as e: - logger.error(f"获取详细状态失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取详细状态失败") @simulation_bp.route('//actions', methods=['GET']) @@ -1902,12 +1808,7 @@ def get_simulation_actions(simulation_id: str): }) except Exception as e: - logger.error(f"获取动作历史失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取动作历史失败") @simulation_bp.route('//timeline', methods=['GET']) @@ -1942,12 +1843,7 @@ def get_simulation_timeline(simulation_id: str): }) except Exception as e: - logger.error(f"获取时间线失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取时间线失败") @simulation_bp.route('//agent-stats', methods=['GET']) @@ -1969,12 +1865,7 @@ def get_agent_stats(simulation_id: str): }) except Exception as e: - logger.error(f"获取Agent统计失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取Agent统计失败") # ============== 数据库查询接口 ============== @@ -2049,12 +1940,7 @@ def get_simulation_posts(simulation_id: str): }) except Exception as e: - logger.error(f"获取帖子失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取帖子失败") @simulation_bp.route('//comments', methods=['GET']) @@ -2124,12 +2010,7 @@ def get_simulation_comments(simulation_id: str): }) except Exception as e: - logger.error(f"获取评论失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取评论失败") # ============== Interview 采访接口 ============== @@ -2255,12 +2136,7 @@ def interview_agent(): }), 504 except Exception as e: - logger.error(f"Interview失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "Interview失败") @simulation_bp.route('/interview/batch', methods=['POST']) @@ -2393,12 +2269,7 @@ def interview_agents_batch(): }), 504 except Exception as e: - logger.error(f"批量Interview失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "批量Interview失败") @simulation_bp.route('/interview/all', methods=['POST']) @@ -2496,12 +2367,7 @@ def interview_all_agents(): }), 504 except Exception as e: - logger.error(f"全局Interview失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "全局Interview失败") @simulation_bp.route('/interview/history', methods=['POST']) @@ -2568,12 +2434,7 @@ def get_interview_history(): }) except Exception as e: - logger.error(f"获取Interview历史失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取Interview历史失败") @simulation_bp.route('/env-status', methods=['POST']) @@ -2633,12 +2494,7 @@ def get_env_status(): }) except Exception as e: - logger.error(f"获取环境状态失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "获取环境状态失败") @simulation_bp.route('/close-env', methods=['POST']) @@ -2703,9 +2559,4 @@ def close_simulation_env(): }), 400 except Exception as e: - logger.error(f"关闭环境失败: {str(e)}") - return jsonify({ - "success": False, - "error": str(e), - "traceback": traceback.format_exc() - }), 500 + return handle_api_exception(logger, e, "关闭环境失败") diff --git a/backend/app/utils/__init__.py b/backend/app/utils/__init__.py index 5848792b..5e9bc9f6 100644 --- a/backend/app/utils/__init__.py +++ b/backend/app/utils/__init__.py @@ -2,8 +2,8 @@ 工具模块 """ +from .error_handler import error_response, handle_api_exception, log_error from .file_parser import FileParser from .llm_client import LLMClient -__all__ = ['FileParser', 'LLMClient'] - +__all__ = ['FileParser', 'LLMClient', 'error_response', 'handle_api_exception', 'log_error'] diff --git a/backend/app/utils/error_handler.py b/backend/app/utils/error_handler.py new file mode 100644 index 00000000..6d78c3bd --- /dev/null +++ b/backend/app/utils/error_handler.py @@ -0,0 +1,47 @@ +""" +Shared API error handling helpers. +""" + +from __future__ import annotations + +import traceback +from typing import Optional + +from flask import jsonify + +from ..config import Config + + +def error_response( + message: str, + status_code: int = 500, + *, + include_traceback: Optional[bool] = None, + original_error: Optional[Exception] = None, +): + """Build a consistent JSON error response without leaking tracebacks by default.""" + payload = { + "success": False, + "error": message, + } + + if include_traceback is None: + include_traceback = Config.DEBUG + + if include_traceback and original_error is not None: + payload["traceback"] = traceback.format_exc() + + return jsonify(payload), status_code + + +def log_error(logger, error: Exception, context: str = "") -> None: + """Log the user-facing context plus the full traceback to server logs.""" + message = f"{context}: {error}" if context else str(error) + logger.error(message) + logger.debug(traceback.format_exc()) + + +def handle_api_exception(logger, error: Exception, context: str = ""): + """Log an exception and return the standard API error payload.""" + log_error(logger, error, context) + return error_response(str(error), 500, original_error=error) diff --git a/backend/app/utils/file_parser.py b/backend/app/utils/file_parser.py index 3f1d8ed2..5e46b0c3 100644 --- a/backend/app/utils/file_parser.py +++ b/backend/app/utils/file_parser.py @@ -4,9 +4,12 @@ """ import os +import logging from pathlib import Path from typing import List, Optional +logger = logging.getLogger(__name__) + def _read_text_with_fallback(file_path: str) -> str: """ @@ -39,8 +42,8 @@ def _read_text_with_fallback(file_path: str) -> str: best = from_bytes(data).best() if best and best.encoding: encoding = best.encoding - except Exception: - pass + except Exception as e: + logger.debug("charset_normalizer detection failed: %s", e) # 回退到 chardet if not encoding: @@ -48,8 +51,8 @@ def _read_text_with_fallback(file_path: str) -> str: import chardet result = chardet.detect(data) encoding = result.get('encoding') if result else None - except Exception: - pass + except Exception as e: + logger.debug("chardet detection failed: %s", e) # 最终兜底:使用 UTF-8 + replace if not encoding: @@ -186,4 +189,3 @@ def split_text_into_chunks( start = end - overlap if end < len(text) else len(text) return chunks - diff --git a/backend/tests/test_error_handler.py b/backend/tests/test_error_handler.py new file mode 100644 index 00000000..135d9fac --- /dev/null +++ b/backend/tests/test_error_handler.py @@ -0,0 +1,66 @@ +from flask import Flask + +from app.config import Config +from app.utils.error_handler import error_response, handle_api_exception + + +class FakeLogger: + def __init__(self): + self.errors = [] + self.debugs = [] + + def error(self, message): + self.errors.append(message) + + def debug(self, message): + self.debugs.append(message) + + +def test_error_response_hides_traceback_when_debug_disabled(monkeypatch): + monkeypatch.setattr(Config, "DEBUG", False) + app = Flask(__name__) + + with app.app_context(): + try: + raise RuntimeError("boom") + except RuntimeError as error: + response, status_code = error_response("boom", original_error=error) + + assert status_code == 500 + assert response.get_json() == {"success": False, "error": "boom"} + + +def test_error_response_includes_traceback_when_debug_enabled(monkeypatch): + monkeypatch.setattr(Config, "DEBUG", True) + app = Flask(__name__) + + with app.app_context(): + try: + raise RuntimeError("boom") + except RuntimeError as error: + response, status_code = error_response("boom", original_error=error) + + payload = response.get_json() + + assert status_code == 500 + assert payload["success"] is False + assert payload["error"] == "boom" + assert "traceback" in payload + assert "RuntimeError: boom" in payload["traceback"] + + +def test_handle_api_exception_logs_and_returns_standard_payload(monkeypatch): + monkeypatch.setattr(Config, "DEBUG", False) + app = Flask(__name__) + logger = FakeLogger() + + with app.app_context(): + try: + raise ValueError("bad input") + except ValueError as error: + response, status_code = handle_api_exception(logger, error, "测试上下文") + + assert status_code == 500 + assert response.get_json() == {"success": False, "error": "bad input"} + assert logger.errors == ["测试上下文: bad input"] + assert logger.debugs diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 40a89a35..c07d8906 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:55:28.632940+00:00", + "captured_at": "2026-03-11T06:58:18.808972+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 8a0e6add..54aaa136 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:55:28.633654+00:00` +- Captured: `2026-03-11T06:58:18.809663+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 2550812b..b7579e8f 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:55:27.763557+00:00", + "captured_at": "2026-03-11T06:58:18.232959+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index caffa1d9..3791ec81 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T06:55:27.764126+00:00` +- Captured: `2026-03-11T06:58:18.233507+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index f48046ef..d727b256 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -26,18 +26,20 @@ Last refreshed: `2026-03-11` - `#113` Add Japanese README: safe docs-only cherry-pick; normalized cross-links with the other language READMEs while landing it locally. - `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. +- `#105` Safe subset landed locally: API JSON error responses now use a shared helper that hides traceback details unless `DEBUG` is enabled, while still logging full tracebacks server-side; file-parser encoding fallbacks now emit debug logs instead of silently swallowing detector failures. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. - `#114` Fix API base URL fallback is already superseded locally by the current frontend API client, which now falls back to the runtime origin and also supports `VITE_API_TIMEOUT`. ## Deferred for later review -- `#105` Security and error-handling sweep: high-value, but touches multiple API surfaces and config defaults, so it needs a dedicated pass instead of bundling into a low-risk cherry-pick cycle. +- `#105` Remaining risky subset: default `DEBUG=False`, non-static `SECRET_KEY` generation, and stricter CORS defaults/configuration are still deferred because they can change local/dev or deployed behavior and need a compatibility review before landing. ## Validation status - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. +- `./.tmp-test-venv/bin/pytest backend/tests/test_error_handler.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py backend/tests/test_ontology_generator.py -q` passes after landing the safe subset of `#105`. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. From 61436e6913975b88a264aaae20aa9101f6691606 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:04:53 +0000 Subject: [PATCH 020/373] fix: handle failed simulation status --- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 2 ++ frontend/src/components/Step3Simulation.vue | 10 +++++++++- 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index c07d8906..22651f94 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T06:58:18.808972+00:00", + "captured_at": "2026-03-11T07:03:04.013498+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 54aaa136..5b6ee620 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T06:58:18.809663+00:00` +- Captured: `2026-03-11T07:03:04.014193+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index b7579e8f..b2ce435b 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T06:58:18.232959+00:00", + "captured_at": "2026-03-11T07:03:03.090137+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 3791ec81..d456a44e 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T06:58:18.233507+00:00` +- Captured: `2026-03-11T07:03:03.090688+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index d727b256..e46180f4 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -26,6 +26,7 @@ Last refreshed: `2026-03-11` - `#113` Add Japanese README: safe docs-only cherry-pick; normalized cross-links with the other language READMEs while landing it locally. - `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. +- `#15` Handle failed simulation status in `Step3Simulation`: stop polling and surface an error instead of leaving the UI stuck in a running state. - `#105` Safe subset landed locally: API JSON error responses now use a shared helper that hides traceback details unless `DEBUG` is enabled, while still logging full tracebacks server-side; file-parser encoding fallbacks now emit debug logs instead of silently swallowing detector failures. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. @@ -38,6 +39,7 @@ Last refreshed: `2026-03-11` - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. +- `cd frontend && npm run build` passes after landing `#15`. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. - `./.tmp-test-venv/bin/pytest backend/tests/test_error_handler.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py backend/tests/test_ontology_generator.py -q` passes after landing the safe subset of `#105`. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. diff --git a/frontend/src/components/Step3Simulation.vue b/frontend/src/components/Step3Simulation.vue index 74d0e1e7..513182c4 100644 --- a/frontend/src/components/Step3Simulation.vue +++ b/frontend/src/components/Step3Simulation.vue @@ -507,6 +507,14 @@ const fetchRunStatus = async () => { addLog(`[Community] R${data.reddit_current_round}/${data.total_rounds} | T:${data.reddit_simulated_hours || 0}h | A:${data.reddit_actions_count}`) prevRedditRound.value = data.reddit_current_round } + + if (data.runner_status === 'failed') { + const errorMsg = data.error || '模拟运行失败' + addLog(`✗ 模拟失败: ${errorMsg}`) + stopPolling() + emit('update-status', 'error') + return + } // 检测模拟是否已完成(通过 runner_status 或平台完成状态判断) const isCompleted = data.runner_status === 'completed' || data.runner_status === 'stopped' @@ -1261,4 +1269,4 @@ onUnmounted(() => { animation: spin 0.8s linear infinite; margin-right: 6px; } - \ No newline at end of file + From 0d7b1064673aabc5f097ed848f499ed42e72894e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:08:09 +0000 Subject: [PATCH 021/373] fix: accept OPENAI_API_BASE_URL alias --- .env.example | 1 + backend/app/config.py | 7 ++++++- backend/tests/test_config.py | 18 ++++++++++++++++++ docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 +++ scripts/test_backend_lite.sh | 1 + 9 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 backend/tests/test_config.py diff --git a/.env.example b/.env.example index e1984b52..007b6659 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ # LLM API配置(支持 OpenAI SDK 格式的任意 LLM API) # 也兼容标准 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL 环境变量 +# 如果外部工具导出的是 OPENAI_API_BASE_URL,后端现在也会自动识别 # 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/ # 注意消耗较大,可先进行小于40轮的模拟尝试 # 如果你已经有 OpenAI / Codex 兼容网关,也可以只设置 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL diff --git a/backend/app/config.py b/backend/app/config.py index 81b02641..f6266e71 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -38,7 +38,12 @@ class Config: # LLM配置(统一使用OpenAI格式) LLM_API_KEY = _env('LLM_API_KEY', 'OPENAI_API_KEY') - LLM_BASE_URL = _env('LLM_BASE_URL', 'OPENAI_BASE_URL', default='https://api.openai.com/v1') + LLM_BASE_URL = _env( + 'LLM_BASE_URL', + 'OPENAI_BASE_URL', + 'OPENAI_API_BASE_URL', + default='https://api.openai.com/v1', + ) LLM_MODEL_NAME = _env('LLM_MODEL_NAME', 'OPENAI_MODEL', default='gpt-4o-mini') LLM_MAX_TOKENS = int(os.environ.get('LLM_MAX_TOKENS', '4096')) diff --git a/backend/tests/test_config.py b/backend/tests/test_config.py new file mode 100644 index 00000000..76ec2410 --- /dev/null +++ b/backend/tests/test_config.py @@ -0,0 +1,18 @@ +import importlib.util +from pathlib import Path + + +def test_config_accepts_openai_api_base_url_alias(monkeypatch): + monkeypatch.delenv("LLM_BASE_URL", raising=False) + monkeypatch.delenv("OPENAI_BASE_URL", raising=False) + monkeypatch.setenv("OPENAI_API_BASE_URL", "https://codex.example.test/v1") + + config_path = Path(__file__).resolve().parents[1] / "app" / "config.py" + spec = importlib.util.spec_from_file_location("test_config_module", config_path) + assert spec is not None + assert spec.loader is not None + + config_module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(config_module) + + assert config_module.Config.LLM_BASE_URL == "https://codex.example.test/v1" diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 22651f94..2663e849 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:03:04.013498+00:00", + "captured_at": "2026-03-11T07:05:42.501929+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 5b6ee620..ff587fe9 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:03:04.014193+00:00` +- Captured: `2026-03-11T07:05:42.502604+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=35`, `closed=12`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index b2ce435b..55e66072 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:03:03.090137+00:00", + "captured_at": "2026-03-11T07:05:41.664944+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index d456a44e..7a4315c7 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:03:03.090688+00:00` +- Captured: `2026-03-11T07:05:41.665475+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `35` total (`open=35`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index e46180f4..1321cea3 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -30,17 +30,20 @@ Last refreshed: `2026-03-11` - `#105` Safe subset landed locally: API JSON error responses now use a shared helper that hides traceback details unless `DEBUG` is enabled, while still logging full tracebacks server-side; file-parser encoding fallbacks now emit debug logs instead of silently swallowing detector failures. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. +- Backend config now also accepts `OPENAI_API_BASE_URL`, matching the environment variable exported by the standalone simulation runners and some OpenAI-compatible tooling, with regression coverage in the lightweight backend test path. - `#114` Fix API base URL fallback is already superseded locally by the current frontend API client, which now falls back to the runtime origin and also supports `VITE_API_TIMEOUT`. ## Deferred for later review - `#105` Remaining risky subset: default `DEBUG=False`, non-static `SECRET_KEY` generation, and stricter CORS defaults/configuration are still deferred because they can change local/dev or deployed behavior and need a compatibility review before landing. +- `#82` Dependency-only CVE patch is deferred for coordinated review because the open PR only edits `backend/requirements.txt`, while this repo also depends on `backend/pyproject.toml` and `backend/uv.lock`; landing it blindly would leave dependency state inconsistent. ## Validation status - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. - `cd frontend && npm run build` passes after landing `#15`. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. +- `npm run test:backend:lite` passes with the new `OPENAI_API_BASE_URL` regression test included in the default lightweight backend suite. - `./.tmp-test-venv/bin/pytest backend/tests/test_error_handler.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py backend/tests/test_ontology_generator.py -q` passes after landing the safe subset of `#105`. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. diff --git a/scripts/test_backend_lite.sh b/scripts/test_backend_lite.sh index 2b96ed2c..2b7ef31e 100755 --- a/scripts/test_backend_lite.sh +++ b/scripts/test_backend_lite.sh @@ -15,6 +15,7 @@ fi "python-dotenv>=1.0.0" "${VENV_DIR}/bin/pytest" \ + "${ROOT_DIR}/backend/tests/test_config.py" \ "${ROOT_DIR}/backend/tests/test_llm_client.py" \ "${ROOT_DIR}/backend/tests/test_graph_builder.py" \ -q From 667a7c3055ab4c1b2db9447a39a9b830a183342f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:11:20 +0000 Subject: [PATCH 022/373] feat: add safe backend config validation --- backend/app/config.py | 181 +++++++++++++++++++++++++++++++--- backend/tests/test_config.py | 66 +++++++++++-- docs/upstream-all-state.json | 34 +++---- docs/upstream-all-summary.md | 6 +- docs/upstream-open-state.json | 18 +--- docs/upstream-open-summary.md | 6 +- docs/upstream-triage.md | 4 +- 7 files changed, 257 insertions(+), 58 deletions(-) diff --git a/backend/app/config.py b/backend/app/config.py index f6266e71..fd125d3e 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -4,6 +4,10 @@ """ import os +from dataclasses import dataclass, field +from typing import Any +from urllib.parse import urlparse + from dotenv import load_dotenv # 加载项目根目录的 .env 文件 @@ -26,6 +30,60 @@ def _env(*names, default=None): return default +def _int_env(name, default): + """Parse integer environment variables without crashing module import.""" + raw_value = os.environ.get(name) + if raw_value in (None, ''): + return default + try: + return int(raw_value) + except (TypeError, ValueError): + return default + + +def _float_env(name, default): + """Parse float environment variables without crashing module import.""" + raw_value = os.environ.get(name) + if raw_value in (None, ''): + return default + try: + return float(raw_value) + except (TypeError, ValueError): + return default + + +@dataclass +class ConfigValidationResult: + """Structured config validation output.""" + + errors: list[str] = field(default_factory=list) + warnings: list[str] = field(default_factory=list) + info: list[str] = field(default_factory=list) + + @property + def is_valid(self) -> bool: + return not self.errors + + def add_error(self, message: str) -> None: + self.errors.append(message) + + def add_warning(self, message: str) -> None: + self.warnings.append(message) + + def add_info(self, message: str) -> None: + self.info.append(message) + + def to_dict(self) -> dict[str, Any]: + return { + 'is_valid': self.is_valid, + 'errors': self.errors, + 'warnings': self.warnings, + 'info': self.info, + 'error_count': len(self.errors), + 'warning_count': len(self.warnings), + } + + class Config: """Flask配置类""" @@ -45,12 +103,12 @@ class Config: default='https://api.openai.com/v1', ) LLM_MODEL_NAME = _env('LLM_MODEL_NAME', 'OPENAI_MODEL', default='gpt-4o-mini') - LLM_MAX_TOKENS = int(os.environ.get('LLM_MAX_TOKENS', '4096')) + LLM_MAX_TOKENS = _int_env('LLM_MAX_TOKENS', 4096) # Zep配置 ZEP_API_KEY = os.environ.get('ZEP_API_KEY') - ZEP_RETRY_MAX_ATTEMPTS = int(os.environ.get('ZEP_RETRY_MAX_ATTEMPTS', '3')) - ZEP_RETRY_BASE_DELAY_SECONDS = float(os.environ.get('ZEP_RETRY_BASE_DELAY_SECONDS', '2')) + ZEP_RETRY_MAX_ATTEMPTS = _int_env('ZEP_RETRY_MAX_ATTEMPTS', 3) + ZEP_RETRY_BASE_DELAY_SECONDS = _float_env('ZEP_RETRY_BASE_DELAY_SECONDS', 2.0) # 文件上传配置 MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB @@ -62,7 +120,7 @@ class Config: DEFAULT_CHUNK_OVERLAP = 50 # 默认重叠大小 # OASIS模拟配置 - OASIS_DEFAULT_MAX_ROUNDS = int(os.environ.get('OASIS_DEFAULT_MAX_ROUNDS', '10')) + OASIS_DEFAULT_MAX_ROUNDS = _int_env('OASIS_DEFAULT_MAX_ROUNDS', 10) OASIS_SIMULATION_DATA_DIR = os.path.join(os.path.dirname(__file__), '../uploads/simulations') # OASIS平台可用动作配置 @@ -76,16 +134,115 @@ class Config: ] # Report Agent配置 - REPORT_AGENT_MAX_TOOL_CALLS = int(os.environ.get('REPORT_AGENT_MAX_TOOL_CALLS', '5')) - REPORT_AGENT_MAX_REFLECTION_ROUNDS = int(os.environ.get('REPORT_AGENT_MAX_REFLECTION_ROUNDS', '2')) - REPORT_AGENT_TEMPERATURE = float(os.environ.get('REPORT_AGENT_TEMPERATURE', '0.5')) - + REPORT_AGENT_MAX_TOOL_CALLS = _int_env('REPORT_AGENT_MAX_TOOL_CALLS', 5) + REPORT_AGENT_MAX_REFLECTION_ROUNDS = _int_env('REPORT_AGENT_MAX_REFLECTION_ROUNDS', 2) + REPORT_AGENT_TEMPERATURE = _float_env('REPORT_AGENT_TEMPERATURE', 0.5) + @classmethod def validate(cls): """验证必要配置""" - errors = [] + return cls.validate_comprehensive().errors + + @classmethod + def validate_comprehensive(cls): + """Validate configuration without changing startup behavior.""" + result = ConfigValidationResult() + if not cls.LLM_API_KEY: - errors.append("LLM_API_KEY / OPENAI_API_KEY 未配置") + result.add_error("LLM_API_KEY / OPENAI_API_KEY 未配置") if not cls.ZEP_API_KEY: - errors.append("ZEP_API_KEY 未配置") - return errors + result.add_error("ZEP_API_KEY 未配置") + + cls._validate_url( + result, + "LLM_BASE_URL / OPENAI_BASE_URL / OPENAI_API_BASE_URL", + cls.LLM_BASE_URL, + ) + cls._validate_numeric_env(result, "LLM_MAX_TOKENS", minimum=1) + cls._validate_numeric_env(result, "OASIS_DEFAULT_MAX_ROUNDS", minimum=1) + cls._validate_numeric_env(result, "REPORT_AGENT_MAX_TOOL_CALLS", minimum=1) + cls._validate_numeric_env(result, "REPORT_AGENT_MAX_REFLECTION_ROUNDS", minimum=0) + cls._validate_numeric_env( + result, + "REPORT_AGENT_TEMPERATURE", + minimum=0, + maximum=2, + parser=float, + ) + cls._validate_numeric_env(result, "ZEP_RETRY_MAX_ATTEMPTS", minimum=1) + cls._validate_numeric_env( + result, + "ZEP_RETRY_BASE_DELAY_SECONDS", + minimum=0, + parser=float, + ) + + if cls.DEBUG: + result.add_warning("FLASK_DEBUG=True; 不建议在生产环境启用 DEBUG") + if cls.SECRET_KEY == 'mirofish-secret-key': + result.add_warning("SECRET_KEY 使用默认值;生产环境应覆盖") + if not os.path.isdir(cls.UPLOAD_FOLDER): + result.add_info(f"UPLOAD_FOLDER 尚不存在,将在运行时按需创建: {cls.UPLOAD_FOLDER}") + if cls.LLM_MODEL_NAME: + result.add_info(f"LLM_MODEL_NAME={cls.LLM_MODEL_NAME}") + + return result + + @classmethod + def get_config_summary(cls): + """Return a non-sensitive config snapshot for diagnostics.""" + return { + 'llm': { + 'base_url': cls.LLM_BASE_URL, + 'model': cls.LLM_MODEL_NAME, + 'max_tokens': cls.LLM_MAX_TOKENS, + 'configured': bool(cls.LLM_API_KEY), + }, + 'zep': { + 'configured': bool(cls.ZEP_API_KEY), + 'retry_max_attempts': cls.ZEP_RETRY_MAX_ATTEMPTS, + 'retry_base_delay_seconds': cls.ZEP_RETRY_BASE_DELAY_SECONDS, + }, + 'simulation': { + 'default_max_rounds': cls.OASIS_DEFAULT_MAX_ROUNDS, + 'data_dir': cls.OASIS_SIMULATION_DATA_DIR, + }, + 'report_agent': { + 'max_tool_calls': cls.REPORT_AGENT_MAX_TOOL_CALLS, + 'max_reflection_rounds': cls.REPORT_AGENT_MAX_REFLECTION_ROUNDS, + 'temperature': cls.REPORT_AGENT_TEMPERATURE, + }, + 'debug': cls.DEBUG, + } + + @classmethod + def _validate_url(cls, result, name, value): + if not value: + result.add_error(f"{name} 未配置") + return + parsed = urlparse(value) + if parsed.scheme not in {'http', 'https'}: + result.add_error(f"{name} 必须使用 http/https: {value}") + return + if not parsed.netloc: + result.add_error(f"{name} 缺少主机名: {value}") + + @classmethod + def _validate_numeric_env(cls, result, name, minimum=None, maximum=None, parser=int): + raw_value = os.environ.get(name) + if raw_value in (None, ''): + return + try: + value = parser(raw_value) + except (TypeError, ValueError): + result.add_error(f"{name} 必须是合法数字,当前值: {raw_value}") + return + if minimum is not None and value < minimum: + result.add_error(f"{name} 必须 >= {minimum},当前值: {raw_value}") + if maximum is not None and value > maximum: + result.add_error(f"{name} 必须 <= {maximum},当前值: {raw_value}") + + +def validate_on_startup(): + """Compatibility helper for explicit startup validation hooks.""" + return Config.validate_comprehensive().is_valid diff --git a/backend/tests/test_config.py b/backend/tests/test_config.py index 76ec2410..cb884b27 100644 --- a/backend/tests/test_config.py +++ b/backend/tests/test_config.py @@ -1,18 +1,72 @@ import importlib.util +import sys from pathlib import Path -def test_config_accepts_openai_api_base_url_alias(monkeypatch): - monkeypatch.delenv("LLM_BASE_URL", raising=False) - monkeypatch.delenv("OPENAI_BASE_URL", raising=False) - monkeypatch.setenv("OPENAI_API_BASE_URL", "https://codex.example.test/v1") - +def load_config_module(): config_path = Path(__file__).resolve().parents[1] / "app" / "config.py" - spec = importlib.util.spec_from_file_location("test_config_module", config_path) + module_name = "test_config_module" + sys.modules.pop(module_name, None) + spec = importlib.util.spec_from_file_location(module_name, config_path) assert spec is not None assert spec.loader is not None config_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(config_module) + return config_module + + +def test_config_accepts_openai_api_base_url_alias(monkeypatch): + monkeypatch.delenv("LLM_BASE_URL", raising=False) + monkeypatch.delenv("OPENAI_BASE_URL", raising=False) + monkeypatch.setenv("OPENAI_API_BASE_URL", "https://codex.example.test/v1") + + config_module = load_config_module() assert config_module.Config.LLM_BASE_URL == "https://codex.example.test/v1" + + +def test_validate_returns_structured_errors_for_missing_keys(monkeypatch): + monkeypatch.delenv("LLM_API_KEY", raising=False) + monkeypatch.delenv("OPENAI_API_KEY", raising=False) + monkeypatch.delenv("ZEP_API_KEY", raising=False) + + config_module = load_config_module() + + errors = config_module.Config.validate() + + assert isinstance(errors, list) + assert "LLM_API_KEY / OPENAI_API_KEY 未配置" in errors + assert "ZEP_API_KEY 未配置" in errors + + +def test_validate_comprehensive_detects_invalid_url_and_numeric_values(monkeypatch): + monkeypatch.setenv("LLM_API_KEY", "test-key") + monkeypatch.setenv("ZEP_API_KEY", "zep-key") + monkeypatch.setenv("OPENAI_API_BASE_URL", "ftp://example.test") + monkeypatch.setenv("OASIS_DEFAULT_MAX_ROUNDS", "not-a-number") + monkeypatch.setenv("REPORT_AGENT_TEMPERATURE", "9") + + config_module = load_config_module() + result = config_module.Config.validate_comprehensive() + + assert result.is_valid is False + assert any("OPENAI_API_BASE_URL" in error for error in result.errors) + assert "OASIS_DEFAULT_MAX_ROUNDS 必须是合法数字,当前值: not-a-number" in result.errors + assert "REPORT_AGENT_TEMPERATURE 必须 <= 2,当前值: 9" in result.errors + + +def test_validate_comprehensive_reports_debug_warning_and_safe_summary(monkeypatch): + monkeypatch.setenv("LLM_API_KEY", "test-key") + monkeypatch.setenv("ZEP_API_KEY", "zep-key") + monkeypatch.setenv("FLASK_DEBUG", "True") + + config_module = load_config_module() + result = config_module.Config.validate_comprehensive() + summary = config_module.Config.get_config_summary() + + assert any("DEBUG" in warning for warning in result.warnings) + assert summary["llm"]["configured"] is True + assert summary["zep"]["configured"] is True + assert "api_key" not in str(summary).lower() + assert config_module.validate_on_startup() is True diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 2663e849..8e6c5c8f 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,15 +1,15 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:05:42.501929+00:00", + "captured_at": "2026-03-11T07:09:44.857982+00:00", "counts": { "issues": { "closed": 47, "open": 32 }, "pull_requests": { - "open": 35, - "closed": 12 + "closed": 13, + "open": 34 } }, "issues": [ @@ -916,6 +916,20 @@ } ], "pull_requests": [ + { + "number": 120, + "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", + "url": "https://github.com/666ghj/MiroFish/pull/120", + "state": "closed", + "created_at": "2026-03-10T15:41:04Z", + "updated_at": "2026-03-11T07:09:15Z", + "closed_at": "2026-03-11T07:09:15Z", + "merged_at": null, + "head": "main", + "base": "main", + "draft": false, + "author": "28764116" + }, { "number": 105, "title": "fix: security improvements and error handling fixes", @@ -972,20 +986,6 @@ "draft": false, "author": "M-Tlinqinming" }, - { - "number": 120, - "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", - "url": "https://github.com/666ghj/MiroFish/pull/120", - "state": "open", - "created_at": "2026-03-10T15:41:04Z", - "updated_at": "2026-03-11T03:54:11Z", - "closed_at": null, - "merged_at": null, - "head": "main", - "base": "main", - "draft": false, - "author": "28764116" - }, { "number": 129, "title": "fix(report_agent): handle API token overflow crash with context lengt…", diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index ff587fe9..9c4d1229 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,9 +2,9 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:05:42.502604+00:00` +- Captured: `2026-03-11T07:09:44.858671+00:00` - Issues: `79` total (`open=32`, `closed=47`) -- Pull requests: `47` total (`open=35`, `closed=12`) +- Pull requests: `47` total (`open=34`, `closed=13`) ## Recently Updated Issues @@ -21,11 +21,11 @@ ## Recently Updated Pull Requests +- #120 [closed] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) - #105 [open] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) - #132 [open] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) - #131 [open] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) - #130 [open] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) -- #120 [open] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) - #129 [open] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) - #127 [open] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) - #126 [open] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 55e66072..a101ed5f 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,13 +1,13 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:05:41.664944+00:00", + "captured_at": "2026-03-11T07:09:43.846569+00:00", "counts": { "issues": { "open": 32 }, "pull_requests": { - "open": 35 + "open": 34 } }, "issues": [ @@ -439,20 +439,6 @@ "draft": false, "author": "M-Tlinqinming" }, - { - "number": 120, - "title": "fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档", - "url": "https://github.com/666ghj/MiroFish/pull/120", - "state": "open", - "created_at": "2026-03-10T15:41:04Z", - "updated_at": "2026-03-11T03:54:11Z", - "closed_at": null, - "merged_at": null, - "head": "main", - "base": "main", - "draft": false, - "author": "28764116" - }, { "number": 129, "title": "fix(report_agent): handle API token overflow crash with context lengt…", diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 7a4315c7..a59a591f 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,9 +2,9 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:05:41.665475+00:00` +- Captured: `2026-03-11T07:09:43.847105+00:00` - Issues: `32` total (`open=32`, `closed=0`) -- Pull requests: `35` total (`open=35`, `closed=0`) +- Pull requests: `34` total (`open=34`, `closed=0`) ## Recently Updated Issues @@ -25,9 +25,9 @@ - #132 [open] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) - #131 [open] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) - #130 [open] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) -- #120 [open] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) - #129 [open] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) - #127 [open] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) - #126 [open] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) - #125 [open] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) - #124 [open] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) +- #122 [open] fix(llm_client): remove response_format json_object for local LLM compatibility (`fix/lm-studio-json-object-compat` -> `main`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 1321cea3..8dbd4470 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -28,6 +28,7 @@ Last refreshed: `2026-03-11` - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. - `#15` Handle failed simulation status in `Step3Simulation`: stop polling and surface an error instead of leaving the UI stuck in a running state. - `#105` Safe subset landed locally: API JSON error responses now use a shared helper that hides traceback details unless `DEBUG` is enabled, while still logging full tracebacks server-side; file-parser encoding fallbacks now emit debug logs instead of silently swallowing detector failures. +- `#126` Safe subset landed locally: backend config now exposes structured validation helpers and a non-sensitive config summary, while malformed numeric env vars no longer crash module import before validation can report them. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. - Backend config now also accepts `OPENAI_API_BASE_URL`, matching the environment variable exported by the standalone simulation runners and some OpenAI-compatible tooling, with regression coverage in the lightweight backend test path. @@ -43,10 +44,11 @@ Last refreshed: `2026-03-11` - `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. - `cd frontend && npm run build` passes after landing `#15`. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. -- `npm run test:backend:lite` passes with the new `OPENAI_API_BASE_URL` regression test included in the default lightweight backend suite. +- `npm run test:backend:lite` passes with the `OPENAI_API_BASE_URL` regression test plus the new structured config-validation coverage included in the default lightweight backend suite. - `./.tmp-test-venv/bin/pytest backend/tests/test_error_handler.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py backend/tests/test_ontology_generator.py -q` passes after landing the safe subset of `#105`. - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. +- `python3 -m unittest tests/test_sync_upstream_github.py` and refreshed snapshots now show `32` open upstream issues, `34` open upstream PRs, and `13` closed upstream PRs in the full-history capture. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. ## Snapshot artifacts From 63ddb3b0864129a9515d477222cba14bc0d8f338 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:13:32 +0000 Subject: [PATCH 023/373] ci: add ARM64 docker image workflow support --- .github/workflows/docker-image.yml | 5 ++++- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 +++ 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index af8fc23a..49759172 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -39,11 +39,14 @@ jobs: type=sha type=raw,value=latest - - name: Build and push + - name: Build and push (multi-platform) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 8e6c5c8f..1f71a366 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:09:44.857982+00:00", + "captured_at": "2026-03-11T07:12:12.844391+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 9c4d1229..108b522c 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:09:44.858671+00:00` +- Captured: `2026-03-11T07:12:12.845086+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=34`, `closed=13`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index a101ed5f..e7253c30 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:09:43.846569+00:00", + "captured_at": "2026-03-11T07:12:12.072089+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index a59a591f..0cc5b9ce 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:09:43.847105+00:00` +- Captured: `2026-03-11T07:12:12.072673+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `34` total (`open=34`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 8dbd4470..9c3adc90 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -14,6 +14,7 @@ Last refreshed: `2026-03-11` - `#104` Make Vite dev proxy target configurable with `VITE_API_BASE_URL`: removes another hardcoded localhost assumption for custom backend hosts and ports. - `#115` Use SPDX license string: safe metadata-only cherry-pick. - `#116` Upgrade GitHub Actions: safe workflow-only dependency bump. +- `#103` Upgrade Docker image workflow for ARM64 builds: safe workflow-only cherry-pick adding `linux/arm64` image output and GitHub Actions cache configuration. - `#125` Improve new-project network error diagnostics: safe single-file frontend error-message improvement. - `#122` Remove `response_format={"type":"json_object"}` from `chat_json()`: improves compatibility with LM Studio and Ollama-style backends. - `#124` Robust JSON payload extraction: safe parsing hardening plus regression tests. @@ -38,6 +39,8 @@ Last refreshed: `2026-03-11` - `#105` Remaining risky subset: default `DEBUG=False`, non-static `SECRET_KEY` generation, and stricter CORS defaults/configuration are still deferred because they can change local/dev or deployed behavior and need a compatibility review before landing. - `#82` Dependency-only CVE patch is deferred for coordinated review because the open PR only edits `backend/requirements.txt`, while this repo also depends on `backend/pyproject.toml` and `backend/uv.lock`; landing it blindly would leave dependency state inconsistent. +- `#100` Relative frontend API base URL fallback is superseded locally by the current API client, which already falls back to the runtime origin and respects `VITE_API_BASE_URL`. +- `#72` Markdown-fence cleanup for JSON responses is superseded locally by the broader `_extract_json_payload()` handling in `backend/app/utils/llm_client.py`. ## Validation status - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. From 92742e12161eef327c6a7ea9af7259dc34ee5cc0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:19:07 +0000 Subject: [PATCH 024/373] fix: retry failed report generation from report view --- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 + frontend/src/components/Step4Report.vue | 224 +++++++++++++++++++++++- 6 files changed, 226 insertions(+), 9 deletions(-) diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 1f71a366..4d1bb7ad 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:12:12.844391+00:00", + "captured_at": "2026-03-11T07:14:35.653806+00:00", "counts": { "issues": { "closed": 47, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 108b522c..478bc39d 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:12:12.845086+00:00` +- Captured: `2026-03-11T07:14:35.654480+00:00` - Issues: `79` total (`open=32`, `closed=47`) - Pull requests: `47` total (`open=34`, `closed=13`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index e7253c30..ad58ad88 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:12:12.072089+00:00", + "captured_at": "2026-03-11T07:14:35.037704+00:00", "counts": { "issues": { "open": 32 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 0cc5b9ce..3022859e 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:12:12.072673+00:00` +- Captured: `2026-03-11T07:14:35.038248+00:00` - Issues: `32` total (`open=32`, `closed=0`) - Pull requests: `34` total (`open=34`, `closed=0`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 9c3adc90..d6aff8a4 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -28,6 +28,7 @@ Last refreshed: `2026-03-11` - `#73` Sanitize malformed ontology entity/edge items before fallback injection: prevents `_validate_and_process()` crashes on mixed-quality LLM JSON output. - `#74` Replace bare `except:` clauses with `except Exception:` in JSON repair and simulation history formatting paths. - `#15` Handle failed simulation status in `Step3Simulation`: stop polling and surface an error instead of leaving the UI stuck in a running state. +- `#84` Failed report generation can now be retried directly from `Step4Report`: the view polls the persisted report status, surfaces backend error text when generation fails, and offers a `force_regenerate` retry path instead of leaving the user stranded on a dead report page. - `#105` Safe subset landed locally: API JSON error responses now use a shared helper that hides traceback details unless `DEBUG` is enabled, while still logging full tracebacks server-side; file-parser encoding fallbacks now emit debug logs instead of silently swallowing detector failures. - `#126` Safe subset landed locally: backend config now exposes structured validation helpers and a non-sensitive config summary, while malformed numeric env vars no longer crash module import before validation can report them. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. @@ -39,6 +40,7 @@ Last refreshed: `2026-03-11` - `#105` Remaining risky subset: default `DEBUG=False`, non-static `SECRET_KEY` generation, and stricter CORS defaults/configuration are still deferred because they can change local/dev or deployed behavior and need a compatibility review before landing. - `#82` Dependency-only CVE patch is deferred for coordinated review because the open PR only edits `backend/requirements.txt`, while this repo also depends on `backend/pyproject.toml` and `backend/uv.lock`; landing it blindly would leave dependency state inconsistent. +- `#87` and `#86` GitHub Actions-only PRs are superseded locally by the current Docker workflow: their diffs would either partially duplicate already-landed upgrades or regress this branch by removing the ARM64/cache changes that came from `#103`. - `#100` Relative frontend API base URL fallback is superseded locally by the current API client, which already falls back to the runtime origin and respects `VITE_API_BASE_URL`. - `#72` Markdown-fence cleanup for JSON responses is superseded locally by the broader `_extract_json_payload()` handling in `backend/app/utils/llm_client.py`. ## Validation status @@ -46,6 +48,7 @@ Last refreshed: `2026-03-11` - `python3 -m unittest tests/test_sync_upstream_github.py` passes for the GitHub sync script pagination/state summary logic. - `cd frontend && npm run build` passes after landing `#104` and the prior OpenAI-alias compatibility updates. - `cd frontend && npm run build` passes after landing `#15`. +- `cd frontend && npm run build` passes after adding failed-report retry handling in `Step4Report` for upstream issue `#84`. - `npm run test:backend:lite` now provides a repo-native lightweight backend validation path when full `uv` resolution is blocked by Rust/CUDA-heavy dependencies. - `npm run test:backend:lite` passes with the `OPENAI_API_BASE_URL` regression test plus the new structured config-validation coverage included in the default lightweight backend suite. - `./.tmp-test-venv/bin/pytest backend/tests/test_error_handler.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py backend/tests/test_ontology_generator.py -q` passes after landing the safe subset of `#105`. diff --git a/frontend/src/components/Step4Report.vue b/frontend/src/components/Step4Report.vue index 22f2bdcf..c22148f5 100644 --- a/frontend/src/components/Step4Report.vue +++ b/frontend/src/components/Step4Report.vue @@ -65,8 +65,24 @@ + +
+
+ + + + + +
+

Report generation failed

+

{{ failureMessage }}

+ +
+ -
+
@@ -86,7 +102,7 @@
-
+
Sections @@ -105,6 +121,16 @@
+
+
+ Generation stopped + {{ failureMessage }} +
+ +
+
-
+
Waiting for agent activity...
@@ -392,7 +418,7 @@ diff --git a/frontend/src/i18n/index.js b/frontend/src/i18n/index.js new file mode 100644 index 00000000..61acf329 --- /dev/null +++ b/frontend/src/i18n/index.js @@ -0,0 +1,40 @@ +import { createI18n } from 'vue-i18n' +import en from './locales/en' +import zh from './locales/zh' + +const LOCALE_KEY = 'mirofish-locale' + +export const getStoredLocale = () => { + if (typeof window === 'undefined') { + return 'zh' + } + + try { + const locale = window.localStorage.getItem(LOCALE_KEY) + return locale === 'en' || locale === 'zh' ? locale : 'zh' + } catch { + return 'zh' + } +} + +export const setStoredLocale = (locale) => { + if (typeof window === 'undefined') { + return + } + + try { + window.localStorage.setItem(LOCALE_KEY, locale) + } catch { + // Ignore storage failures and keep the in-memory locale. + } +} + +export default createI18n({ + legacy: false, + locale: getStoredLocale(), + fallbackLocale: 'zh', + messages: { + en, + zh, + }, +}) diff --git a/frontend/src/i18n/locales/en.js b/frontend/src/i18n/locales/en.js new file mode 100644 index 00000000..2dd75421 --- /dev/null +++ b/frontend/src/i18n/locales/en.js @@ -0,0 +1,83 @@ +export default { + common: { + loading: 'Loading...', + none: 'None', + }, + nav: { + visitGithub: 'Visit our GitHub', + zh: '中文', + en: 'English', + }, + home: { + tagline: 'Simple & Universal Swarm Intelligence Engine', + version: '/ v0.1-preview', + title1: 'Upload Any Report', + title2: 'Predict the Future Instantly', + desc1: 'With just a paragraph of text, ', + desc2: 'MiroFish', + desc3: ' can automatically generate a parallel world powered by up to ', + desc4: 'millions of Agents', + desc5: ' from the seeds of reality within. Inject variables from a god\'s-eye view and find ', + desc6: '"local optima"', + desc7: ' in complex group interactions under dynamic environments.', + slogan: 'Let the future be rehearsed in Agent swarms, let decisions win after a hundred battles.', + systemStatus: 'System Status', + ready: 'Ready', + readyDesc: 'Prediction engine on standby. Upload unstructured data to initialize a simulation sequence.', + lowCost: 'Low Cost', + lowCostDesc: 'Typical simulations average about $5 per run', + highAvailable: 'High Scale', + highAvailableDesc: 'Supports up to millions of Agents', + workflow: 'Workflow Sequence', + step1Title: 'Graph Build', + step1Desc: 'Reality seed extraction, memory injection, and GraphRAG construction', + step2Title: 'Environment Setup', + step2Desc: 'Entity extraction, persona generation, and simulation parameter injection', + step3Title: 'Simulation', + step3Desc: 'Dual-platform simulation with dynamic memory updates', + step4Title: 'Report Generation', + step4Desc: 'ReportAgent uses tool-assisted reasoning against the post-simulation world', + step5Title: 'Deep Interaction', + step5Desc: 'Talk with any simulated agent or with ReportAgent', + seedLabel: '01 / Reality Seed', + formatHint: 'Supported: PDF, MD, TXT', + dragUpload: 'Drag files to upload', + clickBrowse: 'or click to browse', + inputParams: 'Input Parameters', + promptLabel: '>_ 02 / Simulation Prompt', + promptPlaceholder: '// Describe the simulation or prediction you want in natural language', + engineBadge: 'Engine: MiroFish-V1.0', + startEngine: 'Start Engine', + initializing: 'Initializing...', + }, + mainView: { + graph: 'Graph', + split: 'Split', + workbench: 'Workbench', + stepGraph: 'Graph Build', + stepEnv: 'Environment Setup', + stepSim: 'Simulation', + stepReport: 'Report Generation', + stepInteraction: 'Deep Interaction', + statusReady: 'Ready', + statusBuilding: 'Building Graph', + statusOntology: 'Generating Ontology', + statusInit: 'Initializing', + }, + history: { + title: 'History', + graphBuild: 'Graph Build', + envSetup: 'Environment Setup', + report: 'Report', + moreFiles: ' files', + noFiles: 'No files', + simRequirement: 'Simulation Requirement', + relatedFiles: 'Related Files', + noRelatedFiles: 'No related files', + playback: 'Playback', + graphBuildBtn: 'Graph Build', + envSetupBtn: 'Environment Setup', + reportBtn: 'Report', + playbackHint: 'Step 3 and Step 5 require a live runtime session and cannot be replayed from history.', + }, +} diff --git a/frontend/src/i18n/locales/zh.js b/frontend/src/i18n/locales/zh.js new file mode 100644 index 00000000..707a65b9 --- /dev/null +++ b/frontend/src/i18n/locales/zh.js @@ -0,0 +1,83 @@ +export default { + common: { + loading: '加载中...', + none: '无', + }, + nav: { + visitGithub: '访问我们的Github主页', + zh: '中文', + en: 'English', + }, + home: { + tagline: '简洁通用的群体智能引擎', + version: '/ v0.1-预览版', + title1: '上传任意报告', + title2: '即刻推演未来', + desc1: '即使只有一段文字,', + desc2: 'MiroFish', + desc3: '也能基于其中的现实种子,全自动生成与之对应的至多', + desc4: '百万级Agent', + desc5: '构成的平行世界。通过上帝视角注入变量,在复杂的群体交互中寻找动态环境下的', + desc6: '“局部最优解”', + desc7: '', + slogan: '让未来在 Agent 群中预演,让决策在百战后胜出', + systemStatus: '系统状态', + ready: '准备就绪', + readyDesc: '预测引擎待命中,可上传多份非结构化数据以初始化模拟序列', + lowCost: '低成本', + lowCostDesc: '常规模拟平均5$/次', + highAvailable: '高可用', + highAvailableDesc: '最多百万级Agent模拟', + workflow: '工作流序列', + step1Title: '图谱构建', + step1Desc: '现实种子提取 & 个体与群体记忆注入 & GraphRAG构建', + step2Title: '环境搭建', + step2Desc: '实体关系抽取 & 人设生成 & 环境配置Agent注入仿真参数', + step3Title: '开始模拟', + step3Desc: '双平台并行模拟 & 自动解析预测需求 & 动态更新时序记忆', + step4Title: '报告生成', + step4Desc: 'ReportAgent拥有丰富的工具集与模拟后环境进行深度交互', + step5Title: '深度互动', + step5Desc: '与模拟世界中的任意一位进行对话 & 与ReportAgent进行对话', + seedLabel: '01 / 现实种子', + formatHint: '支持格式: PDF, MD, TXT', + dragUpload: '拖拽文件上传', + clickBrowse: '或点击浏览文件系统', + inputParams: '输入参数', + promptLabel: '>_ 02 / 模拟提示词', + promptPlaceholder: '// 用自然语言输入模拟或预测需求', + engineBadge: '引擎: MiroFish-V1.0', + startEngine: '启动引擎', + initializing: '初始化中...', + }, + mainView: { + graph: '图谱', + split: '双栏', + workbench: '工作台', + stepGraph: '图谱构建', + stepEnv: '环境搭建', + stepSim: '开始模拟', + stepReport: '报告生成', + stepInteraction: '深度互动', + statusReady: '准备完成', + statusBuilding: '图谱构建中', + statusOntology: '本体生成中', + statusInit: '初始化中', + }, + history: { + title: '推演记录', + graphBuild: '图谱构建', + envSetup: '环境搭建', + report: '分析报告', + moreFiles: '个文件', + noFiles: '暂无文件', + simRequirement: '模拟需求', + relatedFiles: '关联文件', + noRelatedFiles: '暂无关联文件', + playback: '推演回放', + graphBuildBtn: '图谱构建', + envSetupBtn: '环境搭建', + reportBtn: '分析报告', + playbackHint: 'Step3「开始模拟」与 Step5「深度互动」需在运行中启动,不支持历史回放', + }, +} diff --git a/frontend/src/main.js b/frontend/src/main.js index c8e37b03..cc3d101e 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,9 +1,11 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router' +import i18n from './i18n' const app = createApp(App) app.use(router) +app.use(i18n) app.mount('#app') diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index afe01a0c..da54e2de 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -4,8 +4,9 @@ @@ -15,21 +16,21 @@
- 简洁通用的群体智能引擎 - / v0.1-预览版 + {{ t('home.tagline') }} + {{ t('home.version') }}

- 上传任意报告
- 即刻推演未来 + {{ t('home.title1') }}
+ {{ t('home.title2') }}

- 即使只有一段文字,MiroFish 也能基于其中的现实种子,全自动生成与之对应的至多百万级Agent构成的平行世界。通过上帝视角注入变量,在复杂的群体交互中寻找动态环境下的“局部最优解” + {{ t('home.desc1') }}{{ t('home.desc2') }}{{ t('home.desc3') }}{{ t('home.desc4') }}{{ t('home.desc5') }}{{ t('home.desc6') }}{{ t('home.desc7') }}

- 让未来在 Agent 群中预演,让决策在百战后胜出_ + {{ t('home.slogan') }}_

@@ -53,65 +54,65 @@
- 系统状态 + {{ t('home.systemStatus') }}
-

准备就绪

+

{{ t('home.ready') }}

- 预测引擎待命中,可上传多份非结构化数据以初始化模拟序列 + {{ t('home.readyDesc') }}

-
低成本
-
常规模拟平均5$/次
+
{{ t('home.lowCost') }}
+
{{ t('home.lowCostDesc') }}
-
高可用
-
最多百万级Agent模拟
+
{{ t('home.highAvailable') }}
+
{{ t('home.highAvailableDesc') }}
- 工作流序列 + {{ t('home.workflow') }}
01
-
图谱构建
-
现实种子提取 & 个体与群体记忆注入 & GraphRAG构建
+
{{ t('home.step1Title') }}
+
{{ t('home.step1Desc') }}
02
-
环境搭建
-
实体关系抽取 & 人设生成 & 环境配置Agent注入仿真参数
+
{{ t('home.step2Title') }}
+
{{ t('home.step2Desc') }}
03
-
开始模拟
-
双平台并行模拟 & 自动解析预测需求 & 动态更新时序记忆
+
{{ t('home.step3Title') }}
+
{{ t('home.step3Desc') }}
04
-
报告生成
-
ReportAgent拥有丰富的工具集与模拟后环境进行深度交互
+
{{ t('home.step4Title') }}
+
{{ t('home.step4Desc') }}
05
-
深度互动
-
与模拟世界中的任意一位进行对话 & 与ReportAgent进行对话
+
{{ t('home.step5Title') }}
+
{{ t('home.step5Desc') }}
@@ -124,8 +125,8 @@
- 01 / 现实种子 - 支持格式: PDF, MD, TXT + {{ t('home.seedLabel') }} + {{ t('home.formatHint') }}
-
拖拽文件上传
-
或点击浏览文件系统
+
{{ t('home.dragUpload') }}
+
{{ t('home.clickBrowse') }}
@@ -164,23 +165,23 @@
- 输入参数 + {{ t('home.inputParams') }}
- >_ 02 / 模拟提示词 + {{ t('home.promptLabel') }}
-
引擎: MiroFish-V1.0
+
{{ t('home.engineBadge') }}
@@ -191,8 +192,8 @@ @click="startSimulation" :disabled="!canSubmit || loading" > - 启动引擎 - 初始化中... + {{ t('home.startEngine') }} + {{ t('home.initializing') }}
@@ -208,10 +209,13 @@ From 988019a7a3aa4476d878b247b975e8544bcd2de8 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:52:38 +0000 Subject: [PATCH 032/373] fix: restore dual-port frontend api fallback --- README-EN.md | 4 ++++ README-JA.md | 4 ++++ README-KO.md | 4 ++++ README.md | 4 ++++ docs/upstream-all-state.json | 19 ++++++++++++++++--- docs/upstream-all-summary.md | 6 +++--- docs/upstream-open-state.json | 17 +++++++++++++++-- docs/upstream-open-summary.md | 6 +++--- docs/upstream-triage.md | 5 ++++- frontend/package.json | 3 ++- frontend/src/api/baseUrl.js | 23 +++++++++++++++++++++++ frontend/src/api/index.js | 15 +++++---------- frontend/tests/baseUrl.test.mjs | 32 ++++++++++++++++++++++++++++++++ 13 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 frontend/src/api/baseUrl.js create mode 100644 frontend/tests/baseUrl.test.mjs diff --git a/README-EN.md b/README-EN.md index f09254df..3b32d6b1 100644 --- a/README-EN.md +++ b/README-EN.md @@ -267,6 +267,8 @@ npm run dev - Frontend: `http://localhost:3000` - Backend API: `http://localhost:5001` +If you use the default dual-port layout, the frontend auto-targets backend port `5001` on the same host. The backend root is API-only; use `http://localhost:5001/health` for a quick health check. + **Start Individually:** ```bash @@ -296,6 +298,8 @@ docker compose up -d Reads `.env` from root directory by default, maps ports `3000 (frontend) / 5001 (backend)` +If you deploy frontend and backend on different hosts or ports, set `VITE_API_BASE_URL` for the frontend explicitly. + > Mirror address for faster pulling is provided as comments in `docker-compose.yml`, replace if needed. ## 📬 Join the Conversation diff --git a/README-JA.md b/README-JA.md index 49991f14..b8334960 100644 --- a/README-JA.md +++ b/README-JA.md @@ -155,6 +155,8 @@ npm run dev - フロントエンド: `http://localhost:3000` - バックエンド API: `http://localhost:5001` +デフォルトの 2 ポート構成では、フロントエンドは同一ホストのバックエンド `5001` を自動参照します。バックエンドのルートは API 用なので、疎通確認は `http://localhost:5001/health` を使用してください。 + **個別に起動:** ```bash @@ -174,6 +176,8 @@ docker compose up -d デフォルトでルートディレクトリの `.env` を読み取り、ポート `3000(フロントエンド)/ 5001(バックエンド)` をマッピング +フロントエンドとバックエンドを別ホストまたは別ポートで運用する場合は、フロントエンド側で `VITE_API_BASE_URL` を明示設定してください。 + > 高速プル用のミラーアドレスが `docker-compose.yml` にコメントとして記載されています。必要に応じて差し替えてください。 ## 📬 コミュニティに参加 diff --git a/README-KO.md b/README-KO.md index ed612966..397d1be3 100644 --- a/README-KO.md +++ b/README-KO.md @@ -157,6 +157,8 @@ npm run dev - 프런트엔드: `http://localhost:3000` - 백엔드 API: `http://localhost:5001` +기본 2포트 구성에서는 프런트엔드가 같은 호스트의 백엔드 `5001` 포트를 자동으로 사용합니다. 백엔드 루트는 API 전용이므로 상태 확인은 `http://localhost:5001/health` 를 사용하세요. + **개별 실행** ```bash @@ -176,6 +178,8 @@ docker compose up -d 기본적으로 루트 디렉터리의 `.env`를 읽고 `3000(프런트엔드) / 5001(백엔드)` 포트를 매핑합니다. +프런트엔드와 백엔드를 서로 다른 호스트나 포트에 배포한다면 프런트엔드에서 `VITE_API_BASE_URL` 을 명시적으로 설정하세요. + > 더 빠른 이미지 풀링을 위한 미러 주소가 `docker-compose.yml` 주석에 포함되어 있으니 필요에 맞게 바꿔 사용할 수 있습니다. ## 📬 커뮤니티 및 문의 diff --git a/README.md b/README.md index 7930c7b9..0c50b463 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,8 @@ npm run dev - 前端:`http://localhost:3000` - 后端 API:`http://localhost:5001` +默认前后端双端口部署时,前端会自动访问同主机的 `5001` 端口后端。后端根路径仅提供 API,快速健康检查请访问 `http://localhost:5001/health`。 + **单独启动:** ```bash @@ -296,6 +298,8 @@ docker compose up -d 默认会读取根目录下的 `.env`,并映射端口 `3000(前端)/5001(后端)` +如果前后端部署在不同主机或不同端口,请为前端显式设置 `VITE_API_BASE_URL`。 + > 在 `docker-compose.yml` 中已通过注释提供加速镜像地址,可按需替换 ## 📬 更多交流 diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 0931c06f..74560b03 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,11 +1,11 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:45:30.701859+00:00", + "captured_at": "2026-03-11T07:49:28.870620+00:00", "counts": { "issues": { - "closed": 47, - "open": 32 + "open": 33, + "closed": 47 }, "pull_requests": { "closed": 14, @@ -13,6 +13,19 @@ } }, "issues": [ + { + "number": 133, + "title": "本地部署,启动已经显示成功了,访问却失败", + "url": "https://github.com/666ghj/MiroFish/issues/133", + "state": "open", + "created_at": "2026-03-11T07:45:16Z", + "updated_at": "2026-03-11T07:47:36Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "Axing93" + }, { "number": 121, "title": "卡在了Exception in handleNewProject: Network Error", diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 9b35f5f6..62ef8ba5 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,12 +2,13 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:45:30.702681+00:00` -- Issues: `79` total (`open=32`, `closed=47`) +- Captured: `2026-03-11T07:49:28.871457+00:00` +- Issues: `80` total (`open=33`, `closed=47`) - Pull requests: `47` total (`open=33`, `closed=14`) ## Recently Updated Issues +- #133 [open] 本地部署,启动已经显示成功了,访问却失败 (question) - #121 [closed] 卡在了Exception in handleNewProject: Network Error (question) - #123 [closed] プリセット業界知識RAGの導入(方式3: ローカルファイル注入) (no labels) - #117 [open] ### Feature Request: English Language Support (enhancement) @@ -17,7 +18,6 @@ - #109 [closed] 纯小白看到新闻后本机部署,但似乎Zep额度用完后不知道接下来咋办了 (question) - #42 [open] 项目在3/5开始模拟时会消耗大量内存 (no labels) - #84 [open] 报告生成失败,请问有没有办法重新生成? (question) -- #107 [open] 镜像问题 (no labels) ## Recently Updated Pull Requests diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index 8d2482f0..f4e73062 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,16 +1,29 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:45:21.098429+00:00", + "captured_at": "2026-03-11T07:49:19.056772+00:00", "counts": { "issues": { - "open": 32 + "open": 33 }, "pull_requests": { "open": 33 } }, "issues": [ + { + "number": 133, + "title": "本地部署,启动已经显示成功了,访问却失败", + "url": "https://github.com/666ghj/MiroFish/issues/133", + "state": "open", + "created_at": "2026-03-11T07:45:16Z", + "updated_at": "2026-03-11T07:47:36Z", + "closed_at": null, + "labels": [ + "question" + ], + "author": "Axing93" + }, { "number": 117, "title": "### Feature Request: English Language Support", diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 2e8b813d..ef2d4b65 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,12 +2,13 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:45:21.099037+00:00` -- Issues: `32` total (`open=32`, `closed=0`) +- Captured: `2026-03-11T07:49:19.057406+00:00` +- Issues: `33` total (`open=33`, `closed=0`) - Pull requests: `33` total (`open=33`, `closed=0`) ## Recently Updated Issues +- #133 [open] 本地部署,启动已经显示成功了,访问却失败 (question) - #117 [open] ### Feature Request: English Language Support (enhancement) - #110 [open] 阿里云百炼 API 调用异常:付费计划(Coding Plan)非千文模型及大模型API中转站的API均失效,仅免费额度模型或coding plan的千文模型可用 (LLM API) - #64 [open] 一直卡在上传文件错误:Request failed with status code 500 (no labels) @@ -17,7 +18,6 @@ - #107 [open] 镜像问题 (no labels) - #99 [open] Docker镜像没有arm版本 (enhancement) - #93 [open] `frontend/src/api/index.js`中的`baseURL`不应该硬编码 (enhancement) -- #92 [open] Upgrade GitHub Actions (enhancement) ## Recently Updated Pull Requests diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index a1be63c6..5d9a0d0f 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -41,6 +41,7 @@ Last refreshed: `2026-03-11` - Upstream issue `#32` is now covered end-to-end locally: when an OpenAI-compatible backend rejects `response_format={"type":"json_object"}`, `OasisProfileGenerator` and `SimulationConfigGenerator` retry without JSON mode and still parse the returned JSON payload. That closes the remaining high-signal backend compatibility gap for direct Codex/OpenAI-compatible setups. - `#114` Fix API base URL fallback is already superseded locally by the current frontend API client, which now falls back to the runtime origin and also supports `VITE_API_TIMEOUT`. - `#93` Hardcoded frontend API base URL is now fully addressed locally: `Process.vue` uses the shared frontend API resolver instead of embedding a separate `http://localhost:5001` fallback in network-error messages. +- Upstream issue `#133` is now addressed locally: when the frontend is served on the documented default port `3000` without an explicit `VITE_API_BASE_URL`, it now auto-targets backend port `5001` on the same host instead of calling the frontend origin and failing in dual-port Docker/local deployments. The READMEs now also point users to `http://localhost:5001/health` instead of expecting the backend root to serve a page. - `#101` Robust JSON helper utilities are now mirrored into the fork for visibility, but the upstream branch predates substantial local/frontend/backend hardening on this branch; a blind cherry-pick would effectively revert large amounts of newer work, and the useful intent is already covered locally by broader JSON payload extraction and compatibility fixes. ## Deferred for later review @@ -68,7 +69,9 @@ Last refreshed: `2026-03-11` - `./.tmp-test-venv/bin/pytest backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes with targeted regression coverage for context-length handling and transient Zep retry behavior. - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. - `python3 -m unittest tests/test_sync_upstream_github.py` passes after teaching the sync script to hydrate per-PR details, so the local JSON/markdown snapshots now include real `mergeable_state` metadata instead of `unknown` placeholders. -- `python3 scripts/sync_upstream_github.py --state open ...` and `--state all ...` refreshed the local snapshots again on March 11, 2026; the full-history capture currently shows `32` open upstream issues, `33` open upstream PRs, and `14` closed upstream PRs. +- `python3 scripts/sync_upstream_github.py --state open ...` and `--state all ...` refreshed the local snapshots again on March 11, 2026; the full-history capture currently shows `33` open upstream issues, `33` open upstream PRs, and `14` closed upstream PRs (`47` total PRs in the full snapshot). +- `cd frontend && npm test` passes with new coverage for the frontend API base URL resolver, including the default `3000 -> 5001` dual-port deployment fallback. +- `cd frontend && npm run build` passes after restoring dual-port frontend/backend compatibility for the default local and Docker topology. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. ## Snapshot artifacts diff --git a/frontend/package.json b/frontend/package.json index 7e05e891..bc5916e9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "vite --host", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "test": "node --test tests/*.test.mjs" }, "dependencies": { "axios": "^1.13.2", diff --git a/frontend/src/api/baseUrl.js b/frontend/src/api/baseUrl.js new file mode 100644 index 00000000..f770cf2d --- /dev/null +++ b/frontend/src/api/baseUrl.js @@ -0,0 +1,23 @@ +export const resolveBaseURL = ({ envBaseURL, location } = {}) => { + const trimmedEnvBaseURL = envBaseURL?.trim() + if (trimmedEnvBaseURL) { + return trimmedEnvBaseURL + } + + if (!location) { + return '' + } + + const origin = location.origin || `${location.protocol}//${location.host}` + if (!origin) { + return '' + } + + if (location.port === '3000') { + const backendOrigin = new URL(origin) + backendOrigin.port = '5001' + return backendOrigin.origin + } + + return origin +} diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index f3dc0704..1bf7ddee 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -1,16 +1,11 @@ import axios from 'axios' +import { resolveBaseURL as resolveApiBaseURL } from './baseUrl' export const resolveBaseURL = () => { - const envBaseURL = import.meta.env.VITE_API_BASE_URL - if (envBaseURL && envBaseURL.trim()) { - return envBaseURL - } - - if (typeof window !== 'undefined' && window.location) { - return window.location.origin - } - - return '' + return resolveApiBaseURL({ + envBaseURL: import.meta.env.VITE_API_BASE_URL, + location: typeof window !== 'undefined' ? window.location : undefined + }) } const getApiLocale = () => { diff --git a/frontend/tests/baseUrl.test.mjs b/frontend/tests/baseUrl.test.mjs new file mode 100644 index 00000000..9618b0d9 --- /dev/null +++ b/frontend/tests/baseUrl.test.mjs @@ -0,0 +1,32 @@ +import test from 'node:test' +import assert from 'node:assert/strict' + +import { resolveBaseURL } from '../src/api/baseUrl.js' + +test('prefers explicit VITE_API_BASE_URL', () => { + assert.equal( + resolveBaseURL({ + envBaseURL: ' https://api.example.com/v1 ', + location: new URL('http://localhost:3000') + }), + 'https://api.example.com/v1' + ) +}) + +test('rewrites the documented frontend port 3000 to backend port 5001', () => { + assert.equal( + resolveBaseURL({ + location: new URL('http://127.0.0.1:3000/process') + }), + 'http://127.0.0.1:5001' + ) +}) + +test('keeps same-origin fallback for reverse-proxied deployments', () => { + assert.equal( + resolveBaseURL({ + location: new URL('https://mirofish.example.com/app') + }), + 'https://mirofish.example.com' + ) +}) From 7603bc2e69febe89149b4de2c67ffed6068c83ec Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 07:58:55 +0000 Subject: [PATCH 033/373] feat: track upstream pr mirror status --- .beads/issues.jsonl | 37 ++++++ docs/upstream-all-state.json | 197 ++++++++++++++++++++++------- docs/upstream-all-summary.md | 23 ++-- docs/upstream-open-state.json | 141 ++++++++++++++++----- docs/upstream-open-summary.md | 23 ++-- docs/upstream-triage.md | 8 +- scripts/sync_upstream_github.py | 81 ++++++++++-- tests/test_sync_upstream_github.py | 30 ++++- 8 files changed, 421 insertions(+), 119 deletions(-) create mode 100644 .beads/issues.jsonl diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl new file mode 100644 index 00000000..7aea932d --- /dev/null +++ b/.beads/issues.jsonl @@ -0,0 +1,37 @@ +{"id":"mirofish-ak9","title":"Fix frontend API fallback for dual-port deployments","description":"Upstream issue 666ghj/MiroFish#133 shows the current frontend base URL fallback breaks the documented/default topology where the frontend is served on port 3000 and the backend API is on 5001. The client currently falls back to window.location.origin, which sends production-style frontend requests to the frontend host instead of the backend port when no reverse proxy is present. Patch the fallback to preserve same-origin setups while auto-targeting port 5001 for the documented local/docker layout, then update docs and validate with a frontend build.","status":"closed","priority":1,"issue_type":"bug","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:50:30Z","created_by":"Codex","updated_at":"2026-03-11T07:52:28Z","closed_at":"2026-03-11T07:52:28Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-api","title":"Fallback when JSON mode is unsupported in OpenAI-compatible generators","description":"Objective 7 / upstream issue #32 follow-up. OasisProfileGenerator and SimulationConfigGenerator still required response_format=json_object, which breaks some OpenAI-compatible backends even though base_url/api_key setup is otherwise valid. Add compatibility fallback without broad refactors, cover it with regression tests, and refresh triage/docs.","status":"closed","priority":1,"issue_type":"bug","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:32:51Z","created_by":"Codex","updated_at":"2026-03-11T07:33:49Z","closed_at":"2026-03-11T07:33:49Z","close_reason":"Completed: persona/config generators now retry without response_format=json_object on compatible backends, regression tests added, and triage updated.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-tfl","title":"Honor OPENAI_API_BASE_URL in standalone simulation runners","description":"Objective 7 follow-up: backend config already accepts OPENAI_API_BASE_URL, but backend/scripts/run_parallel_simulation.py, run_reddit_simulation.py, and run_twitter_simulation.py only read LLM_BASE_URL / OPENAI_BASE_URL on input before exporting OPENAI_API_BASE_URL. This breaks direct Codex/OpenAI-compatible backend setup for standalone runs when users only provide OPENAI_API_BASE_URL. Add alias support and regression tests.","status":"closed","priority":1,"issue_type":"bug","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:28:58Z","created_by":"Codex","updated_at":"2026-03-11T07:30:19Z","closed_at":"2026-03-11T07:30:19Z","close_reason":"Completed: standalone simulation runners now accept OPENAI_API_BASE_URL via a shared helper with regression coverage.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-5as","title":"Unblock unstructured CVE remediation from camel-oasis pin","description":"Upstream PR #82 cannot be landed as a real fix because backend/camel-oasis==0.2.5 transitively requires unstructured==0.13.7. A coordinated remediation needs either a compatible camel-oasis upgrade, a vendor patch, or removal/isolation of the vulnerable unstructured path before backend/uv.lock can move to unstructured==0.18.18.","status":"open","priority":1,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:21:33Z","created_by":"Codex","updated_at":"2026-03-11T07:21:33Z","dependencies":[{"issue_id":"mirofish-5as","depends_on_id":"mirofish-6yh","type":"discovered-from","created_at":"2026-03-11T07:21:33Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-4yr","title":"Fallback to gh auth for upstream sync","description":"scripts/sync_upstream_github.py currently hard-fails on anonymous GitHub API rate limits even when the GitHub CLI is authenticated and usable in this environment. Add a safe fallback to use gh api for issue/PR intake when GITHUB_TOKEN/GH_TOKEN is absent, cover it with unit tests, then refresh the upstream summary artifacts.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:20:22Z","created_by":"Codex","updated_at":"2026-03-11T07:21:47Z","closed_at":"2026-03-11T07:21:47Z","close_reason":"Completed: sync script now falls back to authenticated gh api when env tokens are absent, tests cover the fallback, and upstream open/all snapshots were refreshed successfully.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-gba","title":"Allow retry from failed report generation view","description":"Address upstream issue #84 by teaching the report-generation UI to detect a failed report, surface the backend error, and trigger a force_regenerate retry from Step4Report instead of leaving the user stranded on a dead report page.","status":"closed","priority":1,"issue_type":"bug","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:16:40Z","created_by":"Codex","updated_at":"2026-03-11T07:18:46Z","closed_at":"2026-03-11T07:18:46Z","close_reason":"Completed: Step4Report now detects failed report status, surfaces the backend error, and lets the user force-regenerate from the failed report view.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-mfi","title":"Accept OPENAI_API_BASE_URL alias in backend config","description":"Objective 7 follow-up: backend config should honor OPENAI_API_BASE_URL in addition to LLM_BASE_URL and OPENAI_BASE_URL so Codex/OpenAI-compatible tooling and standalone runners behave consistently. Add regression coverage and include it in the lightweight backend test path.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:07:22Z","created_by":"Codex","updated_at":"2026-03-11T07:07:40Z","closed_at":"2026-03-11T07:07:40Z","close_reason":"Implemented OPENAI_API_BASE_URL alias support in backend config, added regression coverage, and included the test in npm run test:backend:lite.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-dpy","title":"Land safe subset of upstream PR #105: hide traceback details from API responses","description":"Implement the low-risk portion of 666ghj/MiroFish#105 only: add a shared backend error-response helper, remove traceback leakage from API JSON responses while preserving debug-mode traceback support, add targeted unit tests, and update triage. Leave CORS/default DEBUG/SECRET_KEY behavior as a separate follow-up because those defaults can change deployment behavior.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:58:49Z","created_by":"Codex","updated_at":"2026-03-11T07:01:55Z","closed_at":"2026-03-11T07:01:55Z","close_reason":"Landed the safe subset of upstream PR #105: shared API error helper, hidden traceback details unless DEBUG is enabled, file-parser fallback diagnostics, targeted tests, and updated triage.","dependencies":[{"issue_id":"mirofish-dpy","depends_on_id":"mirofish-jyo","type":"discovered-from","created_at":"2026-03-11T06:58:48Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-crl","title":"Land low-risk upstream fixes #73 and #74","description":"Evaluate and land the remaining small, reproducible upstream hardening fixes: sanitize malformed ontology entity/edge items from PR #73 and replace bare except clauses with except Exception from PR #74. Add targeted regression coverage for ontology validation and run lightweight backend validation.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:50:58Z","created_by":"Codex","updated_at":"2026-03-11T06:51:54Z","closed_at":"2026-03-11T06:51:54Z","close_reason":"Landed upstream PR #73 and #74 equivalents locally, added ontology regression coverage, refreshed upstream snapshots, and re-ran lightweight backend validation.","dependencies":[{"issue_id":"mirofish-crl","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:50:57Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-o6p","title":"Capture full upstream GitHub issue/PR state locally","description":"Extend scripts/sync_upstream_github.py so local artifacts include all upstream issues and pull requests, not just open items. Preserve compact machine-readable summaries, support pagination, and refresh docs/upstream-open-state.json plus human-readable summaries so evolve passes can triage from complete upstream state.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:42:55Z","created_by":"Codex","updated_at":"2026-03-11T06:45:02Z","closed_at":"2026-03-11T06:45:02Z","close_reason":"Added paginated authenticated upstream sync support, generated full-state issue/PR artifacts, added unit tests, and landed safe docs-only PRs #130 and #132.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-shn","title":"Land safe subset of upstream PR #129 token overflow handling","description":"Evaluate 666ghj/MiroFish#129 and land the low-risk subset: configurable LLM max tokens plus context-overflow retry trimming and report-agent message pruning, with targeted llm_client regression tests and docs updates as needed.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:38:30Z","created_by":"Codex","updated_at":"2026-03-11T06:41:24Z","closed_at":"2026-03-11T06:41:24Z","close_reason":"Landed safe subset of PR #129, mirrored upstream branch, refreshed upstream snapshot, added targeted tests, and fixed direct OPENAI_* alias support in simulation runners","dependencies":[{"issue_id":"mirofish-shn","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:38:30Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-0n7","title":"Land upstream PR #81 configurable frontend API timeout","description":"Cherry-pick or reimplement 666ghj/MiroFish#81, which adds VITE_API_TIMEOUT support for slow local OpenAI-compatible models like Ollama. This is a narrow, low-risk fix for issue #58 and fits the current safe-first merge pass.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:35:53Z","created_by":"Codex","updated_at":"2026-03-11T06:36:37Z","closed_at":"2026-03-11T06:36:37Z","close_reason":"Implemented configurable frontend timeout and documented VITE_API_TIMEOUT","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-2cp","title":"Evaluate upstream PR #131 retry logic for Zep transient failures","description":"Review 666ghj/MiroFish#131 branch feat/zep-retry-mechanism as the next likely bug-fix candidate. Validate whether the retry/backoff logic is safe to cherry-pick or should be reimplemented more narrowly, especially for issues #60 and #75 around Zep connectivity and rate limits.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:34:07Z","created_by":"Codex","updated_at":"2026-03-11T06:48:22Z","closed_at":"2026-03-11T06:48:22Z","close_reason":"Implemented a narrower safe subset of upstream PR #131: transient-only retry/backoff for Zep graph creation, ontology setup, and batch uploads, with targeted backend regression tests.","dependencies":[{"issue_id":"mirofish-2cp","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:34:06Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-jyo","title":"Review upstream PR #105 security hardening sweep","description":"Review 666ghj/MiroFish#105 as a separate pass. It changes config defaults, CORS behavior, error handling, and traceback exposure across multiple APIs, so it should not be bundled into low-risk cherry-pick cycles without targeted validation.","status":"closed","priority":1,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:34:07Z","created_by":"Codex","updated_at":"2026-03-11T07:01:55Z","closed_at":"2026-03-11T07:01:55Z","close_reason":"Reviewed upstream PR #105, landed the safe low-risk error-handling subset locally, and split the remaining behavior-changing defaults/CORS/SECRET_KEY decisions into follow-up issue mirofish-58w.","dependencies":[{"issue_id":"mirofish-jyo","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:34:06Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-49x","title":"Refresh upstream GitHub snapshot and land next safe PR","description":"Evolve pass: sync all open issues/PRs from 666ghj/MiroFish into docs/, evaluate safe open PRs not yet landed on this branch, cherry-pick or implement the smallest safe fix, validate, and push progress.","status":"closed","priority":1,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:33:01Z","created_by":"Codex","updated_at":"2026-03-11T06:34:17Z","closed_at":"2026-03-11T06:34:17Z","close_reason":"Refreshed upstream issue/PR snapshot, landed PR #125 and PR #116 on this branch, queued follow-up review items, and recorded backend validation blocker.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-18v","title":"2026-03-11 upstream sync and backend compatibility","description":"Track upstream intake from 666ghj/MiroFish, mirror selected work into the fork, and land safe compatibility fixes incrementally.","status":"closed","priority":1,"issue_type":"epic","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:52Z","closed_at":"2026-03-11T06:29:52Z","close_reason":"Initial upstream sync and backend compatibility cycle completed","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-18v.1","title":"Snapshot upstream issues and pull requests","description":"Refresh a machine-readable snapshot of open upstream issues and PRs, then summarize the active backlog for the next evolve pass.","status":"closed","priority":1,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:51Z","closed_at":"2026-03-11T06:29:51Z","close_reason":"Generated docs/upstream-open-summary.md and local upstream snapshot via scripts/sync_upstream_github.py","external_ref":"gh:666ghj/MiroFish","dependencies":[{"issue_id":"mirofish-18v.1","depends_on_id":"mirofish-18v","type":"parent-child","created_at":"2026-03-11T06:28:07Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-18v.2","title":"Review and land safe upstream PRs #115/#122/#124/#127","description":"Prefer metadata/config/parsing fixes first. Cherry-pick directly where safe and supersede overlapping changes with a consolidated local patch where necessary.","status":"closed","priority":1,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:51Z","closed_at":"2026-03-11T06:29:51Z","close_reason":"Cherry-picked upstream PR #115 and consolidated safe llm_client fixes from PRs #122/#124/#127","dependencies":[{"issue_id":"mirofish-18v.2","depends_on_id":"mirofish-18v","type":"parent-child","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-18v.4","title":"Support standard OPENAI_* env aliases","description":"Allow MiroFish to use OpenAI/Codex-compatible backends directly via OPENAI_API_KEY, OPENAI_BASE_URL, and OPENAI_MODEL in addition to LLM_* variables.","status":"closed","priority":1,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:51Z","closed_at":"2026-03-11T06:29:51Z","close_reason":"Config now accepts OPENAI_* aliases and docs describe direct OpenAI-compatible backend support","dependencies":[{"issue_id":"mirofish-18v.4","depends_on_id":"mirofish-18v","type":"parent-child","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-9qd","title":"Automate upstream PR mirror status and reconcile stale review tasks","description":"Extend the upstream GitHub intake workflow so it can emit machine-readable fork mirror status for upstream pull requests, use that to mirror any missing clean PR refs that are still relevant, and reconcile stale beads tasks discovered during the refresh pass (for example upstream PR #120 is now closed).","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:55:18Z","created_by":"Codex","updated_at":"2026-03-11T07:58:39Z","closed_at":"2026-03-11T07:58:39Z","close_reason":"Added fork mirror-status annotations to upstream sync artifacts, mirrored the remaining clean non-main open PR refs into origin, refreshed the summaries, and closed the stale PR #120 review task.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-z42","title":"Review upstream PR #118 RAGflow backend support","description":"Evaluate 666ghj/MiroFish#118 now that its head is mirrored locally. The PR is mergeable but large and changes graph APIs, config, simulation services, and docs to support a RAGflow backend, so it needs a dedicated design/risk review before any subset is landed.","status":"open","priority":2,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","updated_at":"2026-03-11T07:43:56Z","dependencies":[{"issue_id":"mirofish-z42","depends_on_id":"mirofish-0l1","type":"discovered-from","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-0l1","title":"Refresh upstream intake and mirror active review branches","description":"Refresh docs/upstream-* machine-readable snapshots from 666ghj/MiroFish, reconcile counts/triage notes, and mirror any still-relevant open upstream PR branches into the fork for review visibility.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:41:07Z","created_by":"Codex","updated_at":"2026-03-11T07:43:58Z","closed_at":"2026-03-11T07:43:58Z","close_reason":"Refreshed upstream issue/PR snapshots, added PR mergeability metadata to the sync artifacts, mirrored upstream PR branches #105/#108/#118 into the fork, and split larger follow-up reviews into dedicated beads tasks.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-57e","title":"Evaluate upstream PR #119 English language support","description":"Assess 666ghj/MiroFish#119 against current branch, cherry-pick if low-risk enough after conflict resolution and validation, or record exact blockers/findings if not.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:23:21Z","created_by":"Codex","updated_at":"2026-03-11T07:26:48Z","closed_at":"2026-03-11T07:26:48Z","close_reason":"Evaluated upstream PR #119, landed a safe frontend/i18n subset locally, and recorded broader localization as follow-up work.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-dkb","title":"Review upstream PR #87 workflow action upgrades","description":"Inspect 666ghj/MiroFish#87, which appears to be a workflow-only GitHub Actions version bump. If the diff is still low-risk after comparison with already-landed PR #116/#103 changes, cherry-pick or document why it is superseded.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:15:03Z","created_by":"Codex","updated_at":"2026-03-11T07:18:46Z","closed_at":"2026-03-11T07:18:46Z","close_reason":"Reviewed: upstream PR #87 is superseded locally because it would partially duplicate prior action bumps and regress this branch by dropping ARM64/cache workflow improvements.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-xvr","title":"Review and land upstream PR #103 Docker ARM64 workflow support","description":"Evaluate 666ghj/MiroFish#103. Current branch already has action-version updates, but the workflow still lacks multi-platform Docker build targets and GHA cache settings. If the diff stays workflow-only and compatible with the existing release pipeline, land the safe subset and mirror the branch to the fork.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:12:54Z","created_by":"Codex","updated_at":"2026-03-11T07:13:26Z","closed_at":"2026-03-11T07:13:26Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-5rs","title":"Review upstream PR #126 custom exceptions/config validation","description":"Evaluate 666ghj/MiroFish#126 against current local branch, land any low-risk subset that still adds value, and record any rejected/high-risk pieces with exact reasons.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:09:25Z","created_by":"Codex","updated_at":"2026-03-11T07:11:14Z","closed_at":"2026-03-11T07:11:14Z","close_reason":"Landed the low-risk subset of upstream PR #126: structured config validation helpers, safe numeric env parsing, and lightweight regression tests; skipped the large unused exception hierarchy.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-6yh","title":"Review upstream PR #82 dependency-only CVE patch","description":"Review 666ghj/MiroFish#82. The current PR only appends unstructured==0.18.18 to backend/requirements.txt, but this repo also uses backend/pyproject.toml and backend/uv.lock. Decide whether a coordinated dependency update is needed and validate impact before landing anything.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:07:22Z","created_by":"Codex","updated_at":"2026-03-11T07:21:47Z","closed_at":"2026-03-11T07:21:47Z","close_reason":"Reviewed upstream PR #82 and attempted a coordinated unstructured==0.18.18 lock refresh. Blocked because camel-oasis==0.2.5 transitively pins unstructured==0.13.7; opened follow-up mirofish-5as for the real remediation path.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-tzw","title":"Review upstream PR #120 layered service refactor","description":"Review 666ghj/MiroFish#120 separately from low-risk cherry-pick passes. The PR is a large service-layout refactor plus TODO docs, so it needs architectural review and targeted validation instead of a blind merge.","status":"closed","priority":2,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:07:22Z","created_by":"Codex","updated_at":"2026-03-11T07:55:18Z","closed_at":"2026-03-11T07:55:18Z","close_reason":"Upstream PR #120 was closed on March 11, 2026 without landing; the old review task is stale and no longer actionable as an open-PR evaluation item.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-6df","title":"Review upstream PR #126 config validation subset","description":"Assess 666ghj/MiroFish#126 for a safe subset worth landing locally. The PR is too large to cherry-pick wholesale, but the config validation and exception additions may contain small low-risk improvements if they can be isolated from broad behavior changes.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:04:17Z","created_by":"Codex","updated_at":"2026-03-11T07:04:44Z","closed_at":"2026-03-11T07:04:44Z","close_reason":"Reviewed upstream PR #126 and found no clear low-risk subset worth landing over the fork's current config layer; defer unless a narrower concrete requirement emerges.","dependencies":[{"issue_id":"mirofish-6df","depends_on_id":"mirofish-630","type":"discovered-from","created_at":"2026-03-11T07:04:16Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-630","title":"Land upstream PR #15 simulation failure status fix","description":"Cherry-pick or reimplement the small safe frontend fix from 666ghj/MiroFish#15 so Step3Simulation stops polling and surfaces an error when runner_status becomes failed instead of hanging in a running state.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:03:36Z","created_by":"Codex","updated_at":"2026-03-11T07:04:17Z","closed_at":"2026-03-11T07:04:17Z","close_reason":"Landed the safe frontend fix from upstream PR #15 locally, validated with a frontend production build, and updated the upstream triage notes.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-58w","title":"Review remaining risky subset of upstream PR #105 defaults","description":"Follow-up to the safe error-handling subset from 666ghj/MiroFish#105. Evaluate whether to adopt the remaining behavior-changing pieces: default DEBUG=False, non-static SECRET_KEY generation, and stricter CORS defaults/configuration. These need deployment-compatibility review and should not be landed blind.","status":"open","priority":2,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:01:33Z","created_by":"Codex","updated_at":"2026-03-11T07:01:33Z","dependencies":[{"issue_id":"mirofish-58w","depends_on_id":"mirofish-jyo","type":"discovered-from","created_at":"2026-03-11T07:01:33Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-xyr","title":"Land remaining safe upstream docs PRs","description":"Evaluate still-open upstream docs-only PRs (#112 Korean README, #113 Japanese README) and cherry-pick the safe ones into the fork branch, then validate docs tree and update triage.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:55:50Z","created_by":"Codex","updated_at":"2026-03-11T06:57:13Z","closed_at":"2026-03-11T06:57:13Z","close_reason":"Landed upstream docs PR #112 and #113 locally, refreshed upstream machine-readable snapshots, and recorded #114 as already superseded locally.","dependencies":[{"issue_id":"mirofish-xyr","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:55:49Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-3sb","title":"Land upstream PR #104 configurable Vite API proxy target","description":"Cherry-pick or reimplement 666ghj/MiroFish#104 so frontend/vite.config.js reads VITE_API_BASE_URL instead of hardcoding localhost:5001, and document the env var in .env.example. Validate with frontend build.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:53:39Z","created_by":"Codex","updated_at":"2026-03-11T06:54:37Z","closed_at":"2026-03-11T06:54:37Z","close_reason":"Implemented and validated with frontend build","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-ba6","title":"Track lightweight backend validation path","description":"Validation follow-up: `cd backend \u0026\u0026 uv run pytest -q` currently fails in this environment while resolving/building heavyweight dependencies, including `tiktoken`, because no Rust compiler is available. Add or document a lighter CI/local validation path for targeted backend unit tests that does not require full CUDA-heavy dependency installation.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:33:31Z","created_by":"Codex","updated_at":"2026-03-11T06:49:40Z","closed_at":"2026-03-11T06:49:40Z","close_reason":"Added a repo-native lightweight backend validation path via scripts/test_backend_lite.sh, npm run test:backend:lite, README docs, and verified it passes.","dependencies":[{"issue_id":"mirofish-ba6","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:33:30Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-18v.3","title":"Mirror selected upstream branches into fork for visibility","description":"Push actively reviewed upstream PR branches into the fork when they are under active review so the fork has branch-level visibility without broad merges.","status":"closed","priority":2,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:51Z","closed_at":"2026-03-11T06:29:51Z","close_reason":"Pushed mirror/upstream-pr-115, mirror/upstream-pr-122, mirror/upstream-pr-124, and mirror/upstream-pr-127 to the fork","dependencies":[{"issue_id":"mirofish-18v.3","depends_on_id":"mirofish-18v","type":"parent-child","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-auf","title":"Review upstream PR #108 Windows installer packaging","description":"Evaluate 666ghj/MiroFish#108 now that its head is mirrored locally. The PR is mergeable but adds installer/build.ps1, installer docs, and release-packaging assumptions for Windows, so it should be reviewed as a standalone distribution feature rather than cherry-picked blindly.","status":"open","priority":3,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","updated_at":"2026-03-11T07:43:56Z","dependencies":[{"issue_id":"mirofish-auf","depends_on_id":"mirofish-0l1","type":"discovered-from","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-0nq","title":"Broaden English localization beyond shell and history views","description":"Follow-up from mirofish-57e / upstream PR #119. The current branch now supports a persisted EN/ZH toggle for the home page, workflow header, history modal, graph-build process view, Step 3 simulation monitor, and Step 4 report-generation shell/report view chrome. Remaining gaps are deeper Step 4/5 content rendering, tool-result parsing copy, and backend-generated messages that are still Chinese-first.","status":"in_progress","priority":3,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:26:48Z","created_by":"Codex","updated_at":"2026-03-11T07:47:52Z","dependencies":[{"issue_id":"mirofish-0nq","depends_on_id":"mirofish-57e","type":"discovered-from","created_at":"2026-03-11T07:26:47Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index 74560b03..a1640744 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:49:28.870620+00:00", + "captured_at": "2026-03-11T07:57:59.554711+00:00", "counts": { "issues": { "open": 33, @@ -10,6 +10,10 @@ "pull_requests": { "closed": 14, "open": 33 + }, + "mirrored_pull_requests": { + "mirrored": 29, + "not_mirrored": 18 } }, "issues": [ @@ -946,7 +950,9 @@ "LLM API", "size:XS" ], - "author": "sjhddh" + "author": "sjhddh", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-127" }, { "number": 120, @@ -964,7 +970,9 @@ "labels": [ "size:XXL" ], - "author": "28764116" + "author": "28764116", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-120" }, { "number": 105, @@ -983,7 +991,9 @@ "documentation", "size:L" ], - "author": "hobostay" + "author": "hobostay", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-105" }, { "number": 132, @@ -1002,7 +1012,9 @@ "documentation", "size:L" ], - "author": "Noblegasesgoo" + "author": "Noblegasesgoo", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-132" }, { "number": 131, @@ -1021,7 +1033,9 @@ "enhancement", "size:L" ], - "author": "EuanTop" + "author": "EuanTop", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-131" }, { "number": 130, @@ -1040,7 +1054,9 @@ "documentation", "size:M" ], - "author": "M-Tlinqinming" + "author": "M-Tlinqinming", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-130" }, { "number": 129, @@ -1059,7 +1075,9 @@ "LLM API", "size:M" ], - "author": "ai-x-builder" + "author": "ai-x-builder", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-129" }, { "number": 126, @@ -1078,7 +1096,9 @@ "enhancement", "size:XXL" ], - "author": "ZaviQ7" + "author": "ZaviQ7", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-126" }, { "number": 125, @@ -1097,7 +1117,9 @@ "enhancement", "size:S" ], - "author": "SergioChan" + "author": "SergioChan", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-125" }, { "number": 124, @@ -1116,7 +1138,9 @@ "LLM API", "size:M" ], - "author": "SergioChan" + "author": "SergioChan", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-124" }, { "number": 122, @@ -1135,7 +1159,9 @@ "LLM API", "size:XS" ], - "author": "ImL1s" + "author": "ImL1s", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-122" }, { "number": 119, @@ -1154,7 +1180,9 @@ "enhancement", "size:XXL" ], - "author": "Pratiyankkumar" + "author": "Pratiyankkumar", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-119" }, { "number": 89, @@ -1173,7 +1201,9 @@ "enhancement", "size:XL" ], - "author": "zzfe-501" + "author": "zzfe-501", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-89" }, { "number": 118, @@ -1193,7 +1223,9 @@ "enhancement", "size:XXL" ], - "author": "pratyush618" + "author": "pratyush618", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-118" }, { "number": 116, @@ -1211,7 +1243,9 @@ "labels": [ "size:XS" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-116" }, { "number": 115, @@ -1229,7 +1263,9 @@ "labels": [ "size:XS" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-115" }, { "number": 114, @@ -1247,7 +1283,9 @@ "labels": [ "size:S" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-114" }, { "number": 113, @@ -1266,7 +1304,9 @@ "documentation", "size:L" ], - "author": "eltociear" + "author": "eltociear", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-113" }, { "number": 112, @@ -1285,7 +1325,9 @@ "documentation", "size:L" ], - "author": "waitle" + "author": "waitle", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-112" }, { "number": 72, @@ -1303,7 +1345,9 @@ "labels": [ "size:S" ], - "author": "MoeclubM" + "author": "MoeclubM", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-72" }, { "number": 108, @@ -1322,7 +1366,9 @@ "enhancement", "size:XL" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-108" }, { "number": 104, @@ -1341,7 +1387,9 @@ "documentation", "size:M" ], - "author": "nil957" + "author": "nil957", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-104" }, { "number": 103, @@ -1360,7 +1408,9 @@ "enhancement", "size:XS" ], - "author": "nil957" + "author": "nil957", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-103" }, { "number": 91, @@ -1378,7 +1428,9 @@ "labels": [ "size:XS" ], - "author": "leon-x-labs" + "author": "leon-x-labs", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-91" }, { "number": 102, @@ -1397,7 +1449,9 @@ "enhancement", "size:XS" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-102" }, { "number": 101, @@ -1416,7 +1470,9 @@ "enhancement", "size:M" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-101" }, { "number": 100, @@ -1435,7 +1491,9 @@ "enhancement", "size:S" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-100" }, { "number": 97, @@ -1454,7 +1512,9 @@ "Memory Layer", "size:XXL" ], - "author": "Jerry050512" + "author": "Jerry050512", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-97" }, { "number": 87, @@ -1472,7 +1532,9 @@ "labels": [ "size:S" ], - "author": "salmanmkc" + "author": "salmanmkc", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-87" }, { "number": 86, @@ -1490,7 +1552,9 @@ "labels": [ "size:XS" ], - "author": "salmanmkc" + "author": "salmanmkc", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-86" }, { "number": 82, @@ -1508,7 +1572,9 @@ "labels": [ "size:XS" ], - "author": "orbisai0security" + "author": "orbisai0security", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-82" }, { "number": 81, @@ -1527,7 +1593,9 @@ "LLM API", "size:XS" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-81" }, { "number": 13, @@ -1543,7 +1611,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "martin0359" + "author": "martin0359", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-13" }, { "number": 74, @@ -1561,7 +1631,9 @@ "labels": [ "size:XS" ], - "author": "haosenwang1018" + "author": "haosenwang1018", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-74" }, { "number": 73, @@ -1580,7 +1652,9 @@ "LLM API", "size:S" ], - "author": "calvinguo721" + "author": "calvinguo721", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-73" }, { "number": 70, @@ -1599,7 +1673,9 @@ "enhancement", "size:XXL" ], - "author": "Jonah-Wu23" + "author": "Jonah-Wu23", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-70" }, { "number": 33, @@ -1615,7 +1691,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "zouyonghe" + "author": "zouyonghe", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-33" }, { "number": 38, @@ -1631,7 +1709,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "SmartisanNaive" + "author": "SmartisanNaive", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-38" }, { "number": 25, @@ -1647,7 +1727,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "Deroino" + "author": "Deroino", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-25" }, { "number": 44, @@ -1663,7 +1745,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "moonhalf-nostar" + "author": "moonhalf-nostar", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-44" }, { "number": 49, @@ -1679,7 +1763,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "Momoyeyu" + "author": "Momoyeyu", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-49" }, { "number": 6, @@ -1695,7 +1781,9 @@ "draft": false, "mergeable_state": "clean", "labels": [], - "author": "jwc19890114" + "author": "jwc19890114", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-6" }, { "number": 15, @@ -1711,7 +1799,9 @@ "draft": false, "mergeable_state": "clean", "labels": [], - "author": "tt-a1i" + "author": "tt-a1i", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-15" }, { "number": 12, @@ -1727,7 +1817,9 @@ "draft": false, "mergeable_state": "unknown", "labels": [], - "author": "666ghj" + "author": "666ghj", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-12" }, { "number": 10, @@ -1743,7 +1835,9 @@ "draft": true, "mergeable_state": "clean", "labels": [], - "author": "666ghj" + "author": "666ghj", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-10" }, { "number": 1, @@ -1759,7 +1853,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "huanchong-99" + "author": "huanchong-99", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-1" }, { "number": 2, @@ -1775,7 +1871,10 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "huanchong-99" + "author": "huanchong-99", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-2" } - ] + ], + "fork_remote": "origin" } diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index 62ef8ba5..f0df7611 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,9 +2,10 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:49:28.871457+00:00` +- Captured: `2026-03-11T07:57:59.555809+00:00` - Issues: `80` total (`open=33`, `closed=47`) - Pull requests: `47` total (`open=33`, `closed=14`) +- Mirrored in `origin`: `29` of `47` PR refs ## Recently Updated Issues @@ -21,13 +22,13 @@ ## Recently Updated Pull Requests -- #127 [closed, mergeable=clean] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) -- #120 [closed, mergeable=clean] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) -- #105 [open, mergeable=clean] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) -- #132 [open, mergeable=clean] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) -- #131 [open, mergeable=clean] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) -- #130 [open, mergeable=clean] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) -- #129 [open, mergeable=clean] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) -- #126 [open, mergeable=clean] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) -- #125 [open, mergeable=clean] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) -- #124 [open, mergeable=clean] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) +- #127 [closed, mergeable=clean, mirrored=yes] Fix potential crash in LLMClient when content is None (`fix/llm-client-none-content` -> `main`) +- #120 [closed, mergeable=clean, mirrored=no] fix: 修复subsystems目录下neo4j_client导入路径错误; feat: 添加TODO.md开发规划文档 (`main` -> `main`) +- #105 [open, mergeable=clean, mirrored=yes] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) +- #132 [open, mergeable=clean, mirrored=yes] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) +- #131 [open, mergeable=clean, mirrored=yes] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) +- #130 [open, mergeable=clean, mirrored=yes] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) +- #129 [open, mergeable=clean, mirrored=yes] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) +- #126 [open, mergeable=clean, mirrored=yes] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) +- #125 [open, mergeable=clean, mirrored=yes] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) +- #124 [open, mergeable=clean, mirrored=yes] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index f4e73062..feaa51fb 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,13 +1,17 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:49:19.056772+00:00", + "captured_at": "2026-03-11T07:58:25.396074+00:00", "counts": { "issues": { "open": 33 }, "pull_requests": { "open": 33 + }, + "mirrored_pull_requests": { + "mirrored": 28, + "not_mirrored": 5 } }, "issues": [ @@ -413,7 +417,9 @@ "documentation", "size:L" ], - "author": "hobostay" + "author": "hobostay", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-105" }, { "number": 132, @@ -432,7 +438,9 @@ "documentation", "size:L" ], - "author": "Noblegasesgoo" + "author": "Noblegasesgoo", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-132" }, { "number": 131, @@ -451,7 +459,9 @@ "enhancement", "size:L" ], - "author": "EuanTop" + "author": "EuanTop", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-131" }, { "number": 130, @@ -470,7 +480,9 @@ "documentation", "size:M" ], - "author": "M-Tlinqinming" + "author": "M-Tlinqinming", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-130" }, { "number": 129, @@ -489,7 +501,9 @@ "LLM API", "size:M" ], - "author": "ai-x-builder" + "author": "ai-x-builder", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-129" }, { "number": 126, @@ -508,7 +522,9 @@ "enhancement", "size:XXL" ], - "author": "ZaviQ7" + "author": "ZaviQ7", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-126" }, { "number": 125, @@ -527,7 +543,9 @@ "enhancement", "size:S" ], - "author": "SergioChan" + "author": "SergioChan", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-125" }, { "number": 124, @@ -546,7 +564,9 @@ "LLM API", "size:M" ], - "author": "SergioChan" + "author": "SergioChan", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-124" }, { "number": 122, @@ -565,7 +585,9 @@ "LLM API", "size:XS" ], - "author": "ImL1s" + "author": "ImL1s", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-122" }, { "number": 119, @@ -584,7 +606,9 @@ "enhancement", "size:XXL" ], - "author": "Pratiyankkumar" + "author": "Pratiyankkumar", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-119" }, { "number": 118, @@ -604,7 +628,9 @@ "enhancement", "size:XXL" ], - "author": "pratyush618" + "author": "pratyush618", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-118" }, { "number": 116, @@ -622,7 +648,9 @@ "labels": [ "size:XS" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-116" }, { "number": 115, @@ -640,7 +668,9 @@ "labels": [ "size:XS" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-115" }, { "number": 114, @@ -658,7 +688,9 @@ "labels": [ "size:S" ], - "author": "ailuntz" + "author": "ailuntz", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-114" }, { "number": 113, @@ -677,7 +709,9 @@ "documentation", "size:L" ], - "author": "eltociear" + "author": "eltociear", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-113" }, { "number": 112, @@ -696,7 +730,9 @@ "documentation", "size:L" ], - "author": "waitle" + "author": "waitle", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-112" }, { "number": 72, @@ -714,7 +750,9 @@ "labels": [ "size:S" ], - "author": "MoeclubM" + "author": "MoeclubM", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-72" }, { "number": 108, @@ -733,7 +771,9 @@ "enhancement", "size:XL" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-108" }, { "number": 104, @@ -752,7 +792,9 @@ "documentation", "size:M" ], - "author": "nil957" + "author": "nil957", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-104" }, { "number": 103, @@ -771,7 +813,9 @@ "enhancement", "size:XS" ], - "author": "nil957" + "author": "nil957", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-103" }, { "number": 102, @@ -790,7 +834,9 @@ "enhancement", "size:XS" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-102" }, { "number": 101, @@ -809,7 +855,9 @@ "enhancement", "size:M" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-101" }, { "number": 100, @@ -828,7 +876,9 @@ "enhancement", "size:S" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-100" }, { "number": 87, @@ -846,7 +896,9 @@ "labels": [ "size:S" ], - "author": "salmanmkc" + "author": "salmanmkc", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-87" }, { "number": 86, @@ -864,7 +916,9 @@ "labels": [ "size:XS" ], - "author": "salmanmkc" + "author": "salmanmkc", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-86" }, { "number": 82, @@ -882,7 +936,9 @@ "labels": [ "size:XS" ], - "author": "orbisai0security" + "author": "orbisai0security", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-82" }, { "number": 81, @@ -901,7 +957,9 @@ "LLM API", "size:XS" ], - "author": "JasonOA888" + "author": "JasonOA888", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-81" }, { "number": 74, @@ -919,7 +977,9 @@ "labels": [ "size:XS" ], - "author": "haosenwang1018" + "author": "haosenwang1018", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-74" }, { "number": 73, @@ -938,7 +998,9 @@ "LLM API", "size:S" ], - "author": "calvinguo721" + "author": "calvinguo721", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-73" }, { "number": 70, @@ -957,7 +1019,9 @@ "enhancement", "size:XXL" ], - "author": "Jonah-Wu23" + "author": "Jonah-Wu23", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-70" }, { "number": 38, @@ -973,7 +1037,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "SmartisanNaive" + "author": "SmartisanNaive", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-38" }, { "number": 49, @@ -989,7 +1055,9 @@ "draft": false, "mergeable_state": "dirty", "labels": [], - "author": "Momoyeyu" + "author": "Momoyeyu", + "fork_mirrored": false, + "fork_mirror_ref": "origin/mirror/upstream-pr-49" }, { "number": 15, @@ -1005,7 +1073,10 @@ "draft": false, "mergeable_state": "clean", "labels": [], - "author": "tt-a1i" + "author": "tt-a1i", + "fork_mirrored": true, + "fork_mirror_ref": "origin/mirror/upstream-pr-15" } - ] + ], + "fork_remote": "origin" } diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index ef2d4b65..6083e9c7 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,9 +2,10 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:49:19.057406+00:00` +- Captured: `2026-03-11T07:58:25.396764+00:00` - Issues: `33` total (`open=33`, `closed=0`) - Pull requests: `33` total (`open=33`, `closed=0`) +- Mirrored in `origin`: `28` of `33` PR refs ## Recently Updated Issues @@ -21,13 +22,13 @@ ## Recently Updated Pull Requests -- #105 [open, mergeable=clean] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) -- #132 [open, mergeable=clean] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) -- #131 [open, mergeable=clean] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) -- #130 [open, mergeable=clean] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) -- #129 [open, mergeable=clean] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) -- #126 [open, mergeable=clean] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) -- #125 [open, mergeable=clean] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) -- #124 [open, mergeable=clean] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) -- #122 [open, mergeable=clean] fix(llm_client): remove response_format json_object for local LLM compatibility (`fix/lm-studio-json-object-compat` -> `main`) -- #119 [open, mergeable=clean] feat: add an option to switch to english language (`language-option` -> `main`) +- #105 [open, mergeable=clean, mirrored=yes] fix: security improvements and error handling fixes (`fix/security-improvements` -> `main`) +- #132 [open, mergeable=clean, mirrored=yes] docs:add simple system architecture part for README-EN.md & README.md (`docs/add-sys-architecture-part` -> `main`) +- #131 [open, mergeable=clean, mirrored=yes] feat(graph_builder): add retry mechanism for Zep Cloud connection failures (`feat/zep-retry-mechanism` -> `main`) +- #130 [open, mergeable=clean, mirrored=yes] docs: 添加贡献指南文档 (`docs/add-pr-guide` -> `main`) +- #129 [open, mergeable=clean, mirrored=yes] fix(report_agent): handle API token overflow crash with context lengt… (`fix/fix-priority-issues-mNNjT` -> `main`) +- #126 [open, mergeable=clean, mirrored=yes] feat: Add custom exceptions and enhanced config validation (`feature/custom-exceptions-and-config-validation` -> `main`) +- #125 [open, mergeable=clean, mirrored=yes] fix: improve new-project network error diagnostics (`fix/issue-121` -> `main`) +- #124 [open, mergeable=clean, mirrored=yes] fix: robust JSON extraction for mixed LLM responses (`fix/issue-64` -> `main`) +- #122 [open, mergeable=clean, mirrored=yes] fix(llm_client): remove response_format json_object for local LLM compatibility (`fix/lm-studio-json-object-compat` -> `main`) +- #119 [open, mergeable=clean, mirrored=yes] feat: add an option to switch to english language (`language-option` -> `main`) diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 5d9a0d0f..55839c9d 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -5,6 +5,7 @@ Last refreshed: `2026-03-11` ## Current focus - Keep reusable local snapshots of `666ghj/MiroFish` open and full issue/PR state. +- Keep fork visibility current by annotating upstream snapshots with mirror status and pushing missing clean PR refs into `origin` when they are still review-relevant. - Land small, low-risk upstream fixes before considering larger feature branches. - Keep OpenAI-compatible backend support verified in both code paths and docs while reviewing the remaining open PR queue. @@ -70,6 +71,7 @@ Last refreshed: `2026-03-11` - `./.tmp-test-venv/bin/pytest backend/tests/test_ontology_generator.py backend/tests/test_llm_client.py backend/tests/test_graph_builder.py -q` passes after landing the ontology validation hardening and exception-scope cleanup. - `python3 -m unittest tests/test_sync_upstream_github.py` passes after teaching the sync script to hydrate per-PR details, so the local JSON/markdown snapshots now include real `mergeable_state` metadata instead of `unknown` placeholders. - `python3 scripts/sync_upstream_github.py --state open ...` and `--state all ...` refreshed the local snapshots again on March 11, 2026; the full-history capture currently shows `33` open upstream issues, `33` open upstream PRs, and `14` closed upstream PRs (`47` total PRs in the full snapshot). +- `python3 scripts/sync_upstream_github.py --state open|all --fork-remote origin ...` now annotates each PR record with `fork_mirrored` / `fork_mirror_ref`; after mirroring the missing clean non-`main` branches, the refreshed snapshots show `28/33` open PRs and `29/47` total PRs mirrored into the fork. - `cd frontend && npm test` passes with new coverage for the frontend API base URL resolver, including the default `3000 -> 5001` dual-port deployment fallback. - `cd frontend && npm run build` passes after restoring dual-port frontend/backend compatibility for the default local and Docker topology. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. @@ -78,11 +80,11 @@ Last refreshed: `2026-03-11` - `docs/upstream-open-state.json` and `docs/upstream-open-summary.md` remain the fast open-work triage view. - `docs/upstream-all-state.json` and `docs/upstream-all-summary.md` now capture the full upstream issue/PR state for historical triage and mirroring decisions. -- `scripts/sync_upstream_github.py` now supports paginated `--state all` refreshes, hydrates PR detail records so machine-readable snapshots include labels plus `mergeable_state`, and uses `GITHUB_TOKEN` / `GH_TOKEN` when available; when those env vars are absent but the GitHub CLI is authenticated, it falls back to `gh api` so upstream intake still works under anonymous API rate limits. +- `scripts/sync_upstream_github.py` now supports paginated `--state all` refreshes, hydrates PR detail records so machine-readable snapshots include labels plus `mergeable_state`, annotates optional fork mirror status via `--fork-remote`, and uses `GITHUB_TOKEN` / `GH_TOKEN` when available; when those env vars are absent but the GitHub CLI is authenticated, it falls back to `gh api` so upstream intake still works under anonymous API rate limits. ## Practical mirror strategy for the fork - Mirror the highest-signal upstream PR branches to the fork when they are under active review. -- Fork visibility now includes `origin/mirror/upstream-pr-101`, `origin/mirror/upstream-pr-105`, `origin/mirror/upstream-pr-108`, `origin/mirror/upstream-pr-118`, `origin/mirror/upstream-pr-126`, `origin/mirror/upstream-pr-130`, `origin/mirror/upstream-pr-131`, and `origin/mirror/upstream-pr-132` in addition to the previously mirrored review branches. +- Fork visibility now includes `origin/mirror/upstream-pr-73`, `origin/mirror/upstream-pr-74`, `origin/mirror/upstream-pr-81`, `origin/mirror/upstream-pr-82`, `origin/mirror/upstream-pr-86`, `origin/mirror/upstream-pr-87`, `origin/mirror/upstream-pr-100`, `origin/mirror/upstream-pr-101`, `origin/mirror/upstream-pr-102`, `origin/mirror/upstream-pr-103`, `origin/mirror/upstream-pr-104`, `origin/mirror/upstream-pr-105`, `origin/mirror/upstream-pr-108`, `origin/mirror/upstream-pr-113`, `origin/mirror/upstream-pr-114`, `origin/mirror/upstream-pr-115`, `origin/mirror/upstream-pr-116`, `origin/mirror/upstream-pr-118`, `origin/mirror/upstream-pr-119`, `origin/mirror/upstream-pr-122`, `origin/mirror/upstream-pr-124`, `origin/mirror/upstream-pr-125`, `origin/mirror/upstream-pr-126`, `origin/mirror/upstream-pr-127`, `origin/mirror/upstream-pr-129`, `origin/mirror/upstream-pr-130`, `origin/mirror/upstream-pr-131`, and `origin/mirror/upstream-pr-132`, plus the older mirrored `origin/mirror/upstream-pr-15`. - Keep detailed execution tracking in local beads issues to avoid spamming the fork with every upstream item. -- Use `scripts/sync_upstream_github.py` to refresh a machine-readable snapshot and a concise markdown summary before each new evolve pass. +- Use `scripts/sync_upstream_github.py --fork-remote origin` to refresh a machine-readable snapshot and a concise markdown summary before each new evolve pass. diff --git a/scripts/sync_upstream_github.py b/scripts/sync_upstream_github.py index a4753ad6..24eb2713 100644 --- a/scripts/sync_upstream_github.py +++ b/scripts/sync_upstream_github.py @@ -6,6 +6,7 @@ import argparse import json import os +import re import shutil import subprocess import sys @@ -116,6 +117,31 @@ def hydrate_pull_requests(owner: str, name: str, pull_requests: list[dict[str, A return hydrated +def list_mirrored_pull_request_numbers(remote: str) -> set[int]: + try: + result = subprocess.run( + [ + "git", + "for-each-ref", + "--format=%(refname:short)", + f"refs/remotes/{remote}/mirror/upstream-pr-*", + "refs/heads/mirror/upstream-pr-*", + ], + check=True, + capture_output=True, + text=True, + ) + except (OSError, subprocess.CalledProcessError) as exc: + raise RuntimeError(f"Unable to inspect mirrored pull request refs for remote {remote!r}") from exc + + mirrored: set[int] = set() + for line in result.stdout.splitlines(): + match = re.search(r"mirror/upstream-pr-(\d+)$", line.strip()) + if match: + mirrored.add(int(match.group(1))) + return mirrored + + def compact_issue(issue: dict[str, object]) -> dict[str, object]: return { "number": issue["number"], @@ -130,9 +156,20 @@ def compact_issue(issue: dict[str, object]) -> dict[str, object]: } -def compact_pr(pr: dict[str, object]) -> dict[str, object]: +def compact_pr( + pr: dict[str, object], + mirrored_pr_numbers: set[int] | None = None, + fork_remote: str | None = None, +) -> dict[str, object]: + number = int(pr["number"]) + fork_mirrored = False + fork_mirror_ref = None + if mirrored_pr_numbers is not None and fork_remote is not None: + fork_mirrored = number in mirrored_pr_numbers + fork_mirror_ref = f"{fork_remote}/mirror/upstream-pr-{number}" + return { - "number": pr["number"], + "number": number, "title": pr["title"], "url": pr["html_url"], "state": pr["state"], @@ -146,6 +183,8 @@ def compact_pr(pr: dict[str, object]) -> dict[str, object]: "mergeable_state": pr.get("mergeable_state"), "labels": [label["name"] for label in pr.get("labels", [])], "author": pr.get("user", {}).get("login"), + "fork_mirrored": fork_mirrored, + "fork_mirror_ref": fork_mirror_ref, } @@ -157,9 +196,17 @@ def summarize_counts(items: list[dict[str, object]]) -> dict[str, int]: return counts -def write_summary(path: Path, repo: str, state: str, issues: list[dict[str, object]], prs: list[dict[str, object]]) -> None: +def write_summary( + path: Path, + repo: str, + state: str, + issues: list[dict[str, object]], + prs: list[dict[str, object]], + fork_remote: str | None = None, +) -> None: issue_counts = summarize_counts(issues) pr_counts = summarize_counts(prs) + mirrored_count = sum(1 for pr in prs if pr.get("fork_mirrored")) lines = [ "# Upstream Triage Snapshot", "", @@ -168,10 +215,10 @@ def write_summary(path: Path, repo: str, state: str, issues: list[dict[str, obje f"- Captured: `{datetime.now(timezone.utc).isoformat()}`", f"- Issues: `{len(issues)}` total (`open={issue_counts.get('open', 0)}`, `closed={issue_counts.get('closed', 0)}`)", f"- Pull requests: `{len(prs)}` total (`open={pr_counts.get('open', 0)}`, `closed={pr_counts.get('closed', 0)}`)", - "", - "## Recently Updated Issues", - "", ] + if fork_remote: + lines.append(f"- Mirrored in `{fork_remote}`: `{mirrored_count}` of `{len(prs)}` PR refs") + lines.extend(["", "## Recently Updated Issues", ""]) for issue in issues[:10]: labels = ", ".join(issue["labels"]) if issue["labels"] else "no labels" @@ -181,8 +228,11 @@ def write_summary(path: Path, repo: str, state: str, issues: list[dict[str, obje for pr in prs[:10]: suffix = " merged" if pr.get("merged_at") else "" mergeable_state = pr.get("mergeable_state") or "unknown" + mirror_suffix = "" + if fork_remote: + mirror_suffix = ", mirrored=yes" if pr.get("fork_mirrored") else ", mirrored=no" lines.append( - f"- #{pr['number']} [{pr['state']}{suffix}, mergeable={mergeable_state}] " + f"- #{pr['number']} [{pr['state']}{suffix}, mergeable={mergeable_state}{mirror_suffix}] " f"{pr['title']} (`{pr['head']}` -> `{pr['base']}`)" ) @@ -197,6 +247,11 @@ def main() -> int: parser.add_argument("--limit", type=int, default=500, help="Maximum items to fetch per collection") parser.add_argument("--output", required=True, help="Path to write machine-readable JSON") parser.add_argument("--summary", required=True, help="Path to write markdown summary") + parser.add_argument( + "--fork-remote", + default=None, + help="Optional git remote name used to annotate whether upstream PR refs are mirrored into the fork", + ) args = parser.parse_args() owner, name = args.repo.split("/", 1) @@ -213,7 +268,8 @@ def main() -> int: issues = [compact_issue(item) for item in issue_items if "pull_request" not in item] pr_details = hydrate_pull_requests(owner, name, pr_items) - prs = [compact_pr(item) for item in pr_details] + mirrored_pr_numbers = list_mirrored_pull_request_numbers(args.fork_remote) if args.fork_remote else None + prs = [compact_pr(item, mirrored_pr_numbers, args.fork_remote) for item in pr_details] payload = { "repo": args.repo, "state": args.state, @@ -225,11 +281,18 @@ def main() -> int: "issues": issues, "pull_requests": prs, } + if args.fork_remote: + mirrored_total = sum(1 for pr in prs if pr["fork_mirrored"]) + payload["fork_remote"] = args.fork_remote + payload["counts"]["mirrored_pull_requests"] = { + "mirrored": mirrored_total, + "not_mirrored": len(prs) - mirrored_total, + } output_path = Path(args.output) output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") - write_summary(Path(args.summary), args.repo, args.state, issues, prs) + write_summary(Path(args.summary), args.repo, args.state, issues, prs, args.fork_remote) print( f"Captured {len(issues)} issues and {len(prs)} pull requests from {args.repo} " diff --git a/tests/test_sync_upstream_github.py b/tests/test_sync_upstream_github.py index 612b3126..99aacc04 100644 --- a/tests/test_sync_upstream_github.py +++ b/tests/test_sync_upstream_github.py @@ -18,6 +18,30 @@ def load_module(): class SyncUpstreamGithubTests(unittest.TestCase): + def test_list_mirrored_pull_request_numbers_reads_remote_and_local_refs(self): + with patch.object( + sync_upstream_github.subprocess, + "run", + return_value=type( + "Completed", + (), + {"stdout": "origin/mirror/upstream-pr-101\nmirror/upstream-pr-102\norigin/main\n"}, + )(), + ) as mocked: + mirrored = sync_upstream_github.list_mirrored_pull_request_numbers("origin") + + self.assertEqual(mirrored, {101, 102}) + self.assertEqual( + mocked.call_args.args[0], + [ + "git", + "for-each-ref", + "--format=%(refname:short)", + "refs/remotes/origin/mirror/upstream-pr-*", + "refs/heads/mirror/upstream-pr-*", + ], + ) + def test_fetch_json_prefers_authenticated_gh_cli_when_no_token(self): with ( patch.object(sync_upstream_github, "has_github_token", return_value=False), @@ -116,7 +140,9 @@ def test_compact_records_include_state_fields(self): "mergeable_state": "clean", "labels": [{"name": "enhancement"}], "user": {"login": "bob"}, - } + }, + mirrored_pr_numbers={11}, + fork_remote="origin", ) self.assertEqual(issue["state"], "closed") @@ -125,6 +151,8 @@ def test_compact_records_include_state_fields(self): self.assertEqual(pr["merged_at"], "2026-01-03T00:00:01Z") self.assertEqual(pr["mergeable_state"], "clean") self.assertEqual(pr["labels"], ["enhancement"]) + self.assertTrue(pr["fork_mirrored"]) + self.assertEqual(pr["fork_mirror_ref"], "origin/mirror/upstream-pr-11") if __name__ == "__main__": From 4cd5eab129ecc8d3f542cb55957b55180f0d5939 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 11 Mar 2026 08:03:20 +0000 Subject: [PATCH 034/373] feat: localize step 5 interaction chrome --- .beads/issues.jsonl | 3 +- docs/upstream-all-state.json | 2 +- docs/upstream-all-summary.md | 2 +- docs/upstream-open-state.json | 2 +- docs/upstream-open-summary.md | 2 +- docs/upstream-triage.md | 3 + frontend/src/components/GraphPanel.vue | 76 +++++------ frontend/src/components/Step5Interaction.vue | 132 ++++++++++--------- frontend/src/i18n/locales/en.js | 105 +++++++++++++++ frontend/src/i18n/locales/zh.js | 105 +++++++++++++++ 10 files changed, 325 insertions(+), 107 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 7aea932d..ca309dd2 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -33,5 +33,6 @@ {"id":"mirofish-3sb","title":"Land upstream PR #104 configurable Vite API proxy target","description":"Cherry-pick or reimplement 666ghj/MiroFish#104 so frontend/vite.config.js reads VITE_API_BASE_URL instead of hardcoding localhost:5001, and document the env var in .env.example. Validate with frontend build.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:53:39Z","created_by":"Codex","updated_at":"2026-03-11T06:54:37Z","closed_at":"2026-03-11T06:54:37Z","close_reason":"Implemented and validated with frontend build","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"mirofish-ba6","title":"Track lightweight backend validation path","description":"Validation follow-up: `cd backend \u0026\u0026 uv run pytest -q` currently fails in this environment while resolving/building heavyweight dependencies, including `tiktoken`, because no Rust compiler is available. Add or document a lighter CI/local validation path for targeted backend unit tests that does not require full CUDA-heavy dependency installation.","status":"closed","priority":2,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T06:33:31Z","created_by":"Codex","updated_at":"2026-03-11T06:49:40Z","closed_at":"2026-03-11T06:49:40Z","close_reason":"Added a repo-native lightweight backend validation path via scripts/test_backend_lite.sh, npm run test:backend:lite, README docs, and verified it passes.","dependencies":[{"issue_id":"mirofish-ba6","depends_on_id":"mirofish-49x","type":"discovered-from","created_at":"2026-03-11T06:33:30Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"mirofish-18v.3","title":"Mirror selected upstream branches into fork for visibility","description":"Push actively reviewed upstream PR branches into the fork when they are under active review so the fork has branch-level visibility without broad merges.","status":"closed","priority":2,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","updated_at":"2026-03-11T06:29:51Z","closed_at":"2026-03-11T06:29:51Z","close_reason":"Pushed mirror/upstream-pr-115, mirror/upstream-pr-122, mirror/upstream-pr-124, and mirror/upstream-pr-127 to the fork","dependencies":[{"issue_id":"mirofish-18v.3","depends_on_id":"mirofish-18v","type":"parent-child","created_at":"2026-03-11T06:28:08Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-1nh","title":"Localize backend/runtime-generated content beyond frontend chrome","description":"Follow-up to mirofish-0nq. The shared graph panel and Step 5 deep-interaction workspace are now localized, but English mode still depends on backend/model-generated payloads that often arrive in Chinese (for example agent bios/professions, backend error strings, and report/runtime content). Continue only with explicit, low-risk localization seams instead of hardcoding translations for generated content.","status":"open","priority":3,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T08:02:57Z","created_by":"Codex","updated_at":"2026-03-11T08:02:57Z","dependencies":[{"issue_id":"mirofish-1nh","depends_on_id":"mirofish-0nq","type":"discovered-from","created_at":"2026-03-11T08:02:56Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"mirofish-auf","title":"Review upstream PR #108 Windows installer packaging","description":"Evaluate 666ghj/MiroFish#108 now that its head is mirrored locally. The PR is mergeable but adds installer/build.ps1, installer docs, and release-packaging assumptions for Windows, so it should be reviewed as a standalone distribution feature rather than cherry-picked blindly.","status":"open","priority":3,"issue_type":"task","owner":"codex@local","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","updated_at":"2026-03-11T07:43:56Z","dependencies":[{"issue_id":"mirofish-auf","depends_on_id":"mirofish-0l1","type":"discovered-from","created_at":"2026-03-11T07:43:56Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"id":"mirofish-0nq","title":"Broaden English localization beyond shell and history views","description":"Follow-up from mirofish-57e / upstream PR #119. The current branch now supports a persisted EN/ZH toggle for the home page, workflow header, history modal, graph-build process view, Step 3 simulation monitor, and Step 4 report-generation shell/report view chrome. Remaining gaps are deeper Step 4/5 content rendering, tool-result parsing copy, and backend-generated messages that are still Chinese-first.","status":"in_progress","priority":3,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:26:48Z","created_by":"Codex","updated_at":"2026-03-11T07:47:52Z","dependencies":[{"issue_id":"mirofish-0nq","depends_on_id":"mirofish-57e","type":"discovered-from","created_at":"2026-03-11T07:26:47Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"mirofish-0nq","title":"Broaden English localization beyond shell and history views","description":"Follow-up from mirofish-57e / upstream PR #119. The current branch now supports a persisted EN/ZH toggle for the home page, workflow header, history modal, graph-build process view, Step 3 simulation monitor, and Step 4 report-generation shell/report view chrome. Remaining gaps are deeper Step 4/5 content rendering, tool-result parsing copy, and backend-generated messages that are still Chinese-first.","status":"closed","priority":3,"issue_type":"task","assignee":"Codex","owner":"codex@local","created_at":"2026-03-11T07:26:48Z","created_by":"Codex","updated_at":"2026-03-11T08:02:57Z","closed_at":"2026-03-11T08:02:57Z","close_reason":"Localized the shared graph panel plus Step 5 deep-interaction chrome, moved the remaining backend/runtime-generated localization gaps into a narrower follow-up.","dependencies":[{"issue_id":"mirofish-0nq","depends_on_id":"mirofish-57e","type":"discovered-from","created_at":"2026-03-11T07:26:47Z","created_by":"Codex","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/docs/upstream-all-state.json b/docs/upstream-all-state.json index a1640744..f4e38a97 100644 --- a/docs/upstream-all-state.json +++ b/docs/upstream-all-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "all", - "captured_at": "2026-03-11T07:57:59.554711+00:00", + "captured_at": "2026-03-11T08:03:00.735373+00:00", "counts": { "issues": { "open": 33, diff --git a/docs/upstream-all-summary.md b/docs/upstream-all-summary.md index f0df7611..d89aff93 100644 --- a/docs/upstream-all-summary.md +++ b/docs/upstream-all-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `all` -- Captured: `2026-03-11T07:57:59.555809+00:00` +- Captured: `2026-03-11T08:03:00.736173+00:00` - Issues: `80` total (`open=33`, `closed=47`) - Pull requests: `47` total (`open=33`, `closed=14`) - Mirrored in `origin`: `29` of `47` PR refs diff --git a/docs/upstream-open-state.json b/docs/upstream-open-state.json index feaa51fb..2999b7b7 100644 --- a/docs/upstream-open-state.json +++ b/docs/upstream-open-state.json @@ -1,7 +1,7 @@ { "repo": "666ghj/MiroFish", "state": "open", - "captured_at": "2026-03-11T07:58:25.396074+00:00", + "captured_at": "2026-03-11T08:02:23.332174+00:00", "counts": { "issues": { "open": 33 diff --git a/docs/upstream-open-summary.md b/docs/upstream-open-summary.md index 6083e9c7..faf1e0dc 100644 --- a/docs/upstream-open-summary.md +++ b/docs/upstream-open-summary.md @@ -2,7 +2,7 @@ - Repository: `666ghj/MiroFish` - State filter: `open` -- Captured: `2026-03-11T07:58:25.396764+00:00` +- Captured: `2026-03-11T08:02:23.332792+00:00` - Issues: `33` total (`open=33`, `closed=0`) - Pull requests: `33` total (`open=33`, `closed=0`) - Mirrored in `origin`: `28` of `33` PR refs diff --git a/docs/upstream-triage.md b/docs/upstream-triage.md index 55839c9d..bb5907e7 100644 --- a/docs/upstream-triage.md +++ b/docs/upstream-triage.md @@ -35,6 +35,7 @@ Last refreshed: `2026-03-11` - `#119` Safe subset landed locally: the frontend now has a persisted `中文` / `English` language toggle for the home shell, main workflow header, and history modal, while API calls include `X-Locale` for future backend localization without forcing the larger upstream backend/UI refactor onto this branch. - Follow-up localization work now also covers the graph-build process view and the Step 3 simulation monitor, so English mode is no longer limited to the shell/history surfaces while broader Step 4/5 and backend-message localization remains open. - Follow-up localization work now also covers the Step 4 report-generation shell and report view chrome, including retry/error/status copy and the report-page header controls, so English mode stays coherent through report generation while deeper Step 4/5 content localization remains open. +- Follow-up localization work now also covers the shared graph panel and the Step 5 deep-interaction workspace chrome: Report Agent chat, agent-selection/survey controls, survey results, graph detail labels, and graph status hints all switch with the persisted `中文` / `English` locale instead of staying Chinese-first. - OpenAI-compatible backend aliases now work in the standalone simulation runners too, so `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` can be used directly outside the Flask app path. - Objective 7 verification status: backend config, standalone runners, and both READMEs now explicitly support direct OpenAI / Codex-compatible / OpenAI-compatible backends without requiring a project-specific raw-key-only setup. - Backend config now also accepts `OPENAI_API_BASE_URL`, matching the environment variable exported by the standalone simulation runners and some OpenAI-compatible tooling, with regression coverage in the lightweight backend test path. @@ -49,6 +50,7 @@ Last refreshed: `2026-03-11` - `#105` Remaining risky subset: default `DEBUG=False`, non-static `SECRET_KEY` generation, and stricter CORS defaults/configuration are still deferred because they can change local/dev or deployed behavior and need a compatibility review before landing. - `#119` Remaining scope is still deferred: most step-level workflow components and backend-generated error text remain Chinese-first, so broader localization should be handled as a follow-up instead of continuing to splice a large, drifting upstream PR into this branch. +- After the latest Step 5 / graph-panel localization pass, the main remaining localization gaps are backend-generated content, agent/profile payload text, and other runtime data that arrives in Chinese from the backend or models rather than from frontend chrome. - `#108` Windows installer packaging is now mirrored into the fork for visibility, but it remains a large Windows-specific feature addition (`installer/build.ps1`, Inno Setup flow, release packaging) and is not a safe blind cherry-pick for this branch. - `#118` RAGflow backend support is now mirrored into the fork for visibility, but it is a large dual-backend feature branch touching graph APIs, config, and simulation services, so it needs a dedicated design/review pass instead of a low-risk merge. - `#82` Dependency-only CVE patch cannot be landed as a real fix yet: a coordinated `uv lock --upgrade-package unstructured==0.18.18` attempt fails because `camel-oasis==0.2.5` transitively pins `unstructured==0.13.7`. The upstream PR also only edits `backend/requirements.txt`, so it would leave this repo's dependency state inconsistent even if cherry-picked. @@ -74,6 +76,7 @@ Last refreshed: `2026-03-11` - `python3 scripts/sync_upstream_github.py --state open|all --fork-remote origin ...` now annotates each PR record with `fork_mirrored` / `fork_mirror_ref`; after mirroring the missing clean non-`main` branches, the refreshed snapshots show `28/33` open PRs and `29/47` total PRs mirrored into the fork. - `cd frontend && npm test` passes with new coverage for the frontend API base URL resolver, including the default `3000 -> 5001` dual-port deployment fallback. - `cd frontend && npm run build` passes after restoring dual-port frontend/backend compatibility for the default local and Docker topology. +- `cd frontend && npm test -- --runInBand` and `cd frontend && npm run build` both pass after localizing the shared graph panel and Step 5 deep-interaction chrome. - `cd backend && uv run pytest -q` is currently blocked in this environment because dependency resolution reaches `tiktoken`, which attempts a source build and fails without a Rust compiler. ## Snapshot artifacts diff --git a/frontend/src/components/GraphPanel.vue b/frontend/src/components/GraphPanel.vue index 314c966e..49baa9cc 100644 --- a/frontend/src/components/GraphPanel.vue +++ b/frontend/src/components/GraphPanel.vue @@ -1,14 +1,14 @@