Commit Graph

110 Commits

Author SHA1 Message Date
Ubuntu 83b69dfd87 fix(graph-api): fix build_graph endpoint for dict-based ProjectManager
Convert all project.attribute accesses to project["key"]/project.get("key"),
use save_project({...}) dict calls, and wire save_graph_record/complete_graph_record
helpers for proper graph persistence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:24:56 +00:00
Ubuntu 5d6d4d787a fix(graph-api): cleanup orphan project on ontology generation failure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:23:15 +00:00
Ubuntu 284f962e17 fix(graph-api): rewrite generate_ontology/import_ontology to use dict ProjectManager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:20:32 +00:00
Ubuntu ea9ac6a1cd fix(graph-api): fix project/task dict access after ProjectManager refactor
Replace .to_dict() calls and attribute access with direct dict usage,
add get_storage() import for delete_project, and rewrite reset_project
to use save_project() with a partial dict instead of mutating an ORM object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:17:21 +00:00
Ubuntu 8a6d00b26e refactor(project): clean up _to_dict delegation and remove unused import
- Remove unused `import io`
- Avoid double-encoding in save_extracted_text by caching encoded bytes
- Delegate _to_dict queries to get_ontology/get_latest_graph_external_id
- Add comment to save_ontology noting full versioning is planned for F2-3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:16:03 +00:00
Ubuntu 949921344b feat(project): add ontology/graph persistence helpers to ProjectManager
- Add `from ..config import Config` import
- Convert `_to_dict` from @staticmethod to @classmethod; it now opens a
  fresh session to populate `ontology` and `graph_id` from OntologyModel
  and GraphModel respectively
- Use `db.expunge(proj)` before closing sessions in create_project,
  get_project and list_projects so `_to_dict` can open its own session
  without nesting conflicts (SQLite StaticPool safe)
- Add five new classmethods: save_ontology, get_ontology,
  save_graph_record, get_latest_graph_external_id, complete_graph_record

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 01:13:26 +00:00
Ubuntu 9ed2412745 test(conftest): add in_memory_db and task manager singleton reset fixtures; fix broken tests
- Replace conftest.py with two autouse fixtures: reset_graph_factory_singleton
  and reset_task_manager_singleton, plus in_memory_db fixture for tests
  requiring a real DB
- Rewrite test_project_task_recovery.py to use ProjectManager + SQLite in-memory
  DB instead of the removed Project dataclass (same guarantee: active_task_id
  persists and defaults to None)
- Fix db.py init_db() to import db_models before Base.metadata.create_all() so
  all ORM tables are registered and created on first startup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 00:15:42 +00:00
Ubuntu 0b760eed0b fix(task): rename loop var t→task_row to avoid shadowing locale.t import 2026-05-03 00:13:12 +00:00
Ubuntu 2478beb9ea feat(project): refactor ProjectManager to persist via SQLAlchemy + StorageService
Replace file-based JSON persistence with SQLAlchemy DB (ProjectModel/ProjectFileModel)
and StorageService for file content; remove Project dataclass; add 7 passing tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 00:11:12 +00:00
Ubuntu 1f43d35d59 feat(task): refactor TaskManager to persist tasks in SQLAlchemy DB
Replace in-memory dict-based TaskManager with a SQLAlchemy-backed implementation
using TaskModel. Tasks now survive process restarts. 6 new tests added and passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 00:10:16 +00:00
Ubuntu 479ae0b712 feat(app): inject SQLAlchemy DB and StorageService into Flask app factory
Initializes the database (via init_db) and registers the StorageService
instance in app.extensions['storage'] inside create_app(). Adds get_storage()
helper for convenient access from any Flask context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 00:08:13 +00:00
Ubuntu 868ce39577 fix(storage,db): path traversal fix, delete_prefix validation, remove dead import, factory uses Config
- local.py: use relative_to() for path traversal guard (fixes prefix-collision false negative)
- local.py: validate delete_prefix rejects empty/root prefix to prevent full-storage wipe
- local.py: remove unused `import os`
- db_models.py: remove dead UniqueConstraint import
- db_models.py: replace deprecated datetime.utcnow() with datetime.now(timezone.utc)
- factory.py: read STORAGE_TYPE and related settings from Config instead of os.environ directly; remove `import os`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 00:06:58 +00:00
Ubuntu 773cc250c9 feat(db): add SQLAlchemy Base, session factory, and all ORM models
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 23:54:05 +00:00
Ubuntu 9e33f823d9 feat(storage): add StorageService protocol, LocalFSStorage, AzureBlobStorage, factory 2026-05-02 23:53:19 +00:00
Ubuntu ca2f9e2a8f feat(config): add DATABASE_URL, STORAGE_TYPE, AZURE_STORAGE_*, JWT config vars 2026-05-02 23:53:16 +00:00
Ubuntu 49f4da51b1 fix(report): strip fabricated tool_result blocks to prevent LLM hallucination loop 2026-04-26 15:06:24 +00:00
Ubuntu 866ed421e2 fix(ontology): handle string attributes from LLM response to prevent TypeError crash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:59:10 +00:00
Ubuntu 117eabf607 feat(recovery): persist active_task_id to project.json for browser-refresh reconnection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:54:44 +00:00
Ubuntu 656a3d7d5c fix(graph): cap get_all_edges to 5000 edges to prevent unbounded RAM growth 2026-04-26 14:50:21 +00:00
Ubuntu d09ee23cd3 feat: ontology import, project recovery, graphiti improvements, and docs
- Add ontology import from file (Step 1)
- Persist active task_id to project.json for browser-refresh recovery
- Add project list endpoint and frontend recovery UI
- Improve Graphiti backend stability and oasis profile generation
- Add TechnicalDesign.md and enterprise roadmap spec
- Update .gitignore to exclude secrets and local-only docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:28:14 +00:00
Ubuntu 7daf8566ed fix(report): eliminate temp file leak in MD fallback; simplify invalid-format test 2026-04-26 00:11:40 +00:00
Ubuntu 8efedb55e5 feat(report): add PDF download endpoint via PyMuPDF
Adds ?format=md|pdf query param to GET /api/report/<id>/download.
PDF is generated from Markdown via fitz.Story (PyMuPDF). Also fixes
create_app() to support dict config and skip JWT auth in TESTING mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 00:07:09 +00:00
Ubuntu a209330b0b debug: log GRAPH_BACKEND and key presence at graph build start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:18:26 +00:00
Ubuntu 09935e53a0 refactor(graph): remove hardcoded ZEP checks, use get_graph_config_errors; add embed/small LLM env docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 21:10:40 +00:00
Ubuntu c074136a87 fix(llm): centralise Azure URL normalisation in parse_azure_url utility
Extract parse_azure_url from graphiti_backend into utils/llm_client so all
services (oasis_profile_generator, simulation_config_generator, graphiti_backend,
LLMClient) strip the /chat/completions suffix and api-version before passing
base_url to the OpenAI SDK, fixing 404 errors when the full Azure endpoint URL
is set in LLM_BASE_URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 21:09:48 +00:00
Ubuntu e7ebcdff75 fix(graphiti): patch _extract_entity_attributes to flatten nested attr dicts
The previous fix applied _flatten_attributes too broadly, breaking graphiti's
internal ExtractedEntities validation (lists were converted to strings).

Instead, monkey-patch only _extract_entity_attributes — the exact function
that returns entity attribute dicts to node.attributes before Neo4j write.
Lists of primitives are preserved; only dict-valued attributes are flattened.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:24:08 +00:00
Ubuntu 6bce05dca2 fix(graphiti): flatten nested attribute dicts before Neo4j write; hide summary from properties panel
Graphiti's attribute extraction LLM sometimes returns values wrapped in
nested dicts ({"value": "CTTI"}) instead of plain strings. Neo4j rejects
these with TypeError: "Property values can only be of primitive types".

Fix: after _AzureGenericClient gets the LLM response, validate it through
the Pydantic response_model and call _flatten_attributes() so every value
reaching Neo4j is a scalar. Also add _flatten_attributes() helper.

UI: exclude 'summary' from the Properties section of the node detail panel
since it already appears in the dedicated Summary section below.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:08:39 +00:00
Ubuntu ba9c8d1f42 feat(ontology): make entity/edge type limits configurable via env vars
Revert default limits back to 10 edges and 12 entities (10 specific + 2
fallback), matching Zep Cloud's maximum. Expose ONTOLOGY_MAX_ENTITY_TYPES
and ONTOLOGY_MAX_EDGE_TYPES in Config so operators can override without
touching code. Prompts now inject the live values at request time.
Also replace Chinese comments in .env.example with English equivalents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:56:44 +00:00
Ubuntu dfabab5343 feat(graph): expand ontology to 20 types, pass attributes to Graphiti, add retry
- ontology_generator: increase entity limit to 20 (18 specific + 2 fallback),
  edge types to 20 (12-20 requested); bump max_tokens to 8192
- ontology_generator: fallback type names (Person/Organization) now resolved
  via i18n so Catalan gets Persona/Organització
- locales: add ontologyFallback* keys to en/zh/es/ca
- graph_builder: pass entity/edge attributes to non-Zep set_ontology (were discarded)
- graphiti_backend: _make_model builds real Pydantic fields per attribute
- graphiti_backend: _build_extraction_instructions includes per-entity attribute
  hints so the LLM knows which fields to extract
- graphiti_backend: add_batch retries up to 3x on "node not found" race condition
  with exponential backoff (2s, 4s) before propagating the error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:19:28 +00:00
Ubuntu 039de4ad8b feat(llm): auto-configure Google AI Studio URL when LLM_PROVIDER=gemini
When LLM_PROVIDER=gemini, LLMClient automatically uses the Google AI Studio
OpenAI-compatible endpoint instead of requiring manual base_url configuration.
An explicit base_url argument still takes precedence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:13:11 +00:00
Ubuntu 788f9c29c9 feat(graph): add GraphitiBackend for Neo4j+graphiti-core local deployment 2026-04-25 13:10:56 +00:00
Ubuntu b2fd7e1b87 refactor(services): replace direct Zep SDK calls with GraphBackend interface 2026-04-25 13:09:59 +00:00
Ubuntu e073ef8716 feat(graph): add GraphBackendFactory singleton 2026-04-25 12:59:56 +00:00
Ubuntu 247ecc86ae feat(graph): add ZepBackend adapter implementing GraphBackend 2026-04-25 11:29:59 +00:00
Ubuntu 0544001fa0 feat(config): add GRAPH_BACKEND + NEO4J_* + LLM_PROVIDER config vars 2026-04-25 11:29:17 +00:00
Ubuntu a75b7cf75a feat(graph): add GraphBackend abstract interface 2026-04-25 11:11:06 +00:00
Ubuntu 7d172b9eec chore(i18n): replace all hardcoded Chinese strings with English in backend
Translate all Chinese comments, docstrings, log messages, error messages,
and LLM prompt text to English across the entire backend codebase.
Locale translation files (locales/*.json) are unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:40:58 +00:00
Ubuntu b5c4d4a336 feat(auth): add JWT login screen, production Dockerfile and Azure Container App Bicep
- Backend: POST /api/auth/login endpoint (PyJWT HS256, 24h expiry)
  require_auth before_request middleware protecting all /api/* routes
  except /login and /health; wsgi.py entry point for gunicorn;
  Flask serves compiled Vue SPA in production
- Frontend: LoginView.vue (MiroFish dark aesthetic), auth.js reactive
  store, Axios Bearer token injection + 401 → /login redirect,
  Vue Router global guard protecting all routes
- i18n: login keys added to en/zh/es/ca locale files
- Dockerfile: multi-stage build (node:20-slim → python:3.11-slim +
  gunicorn), single port 5001
- Azure: container-app.bicep following CTTI guidelines — Log Analytics
  (NOR0016-C 90d retention), Container Apps Environment, all .env vars
  as env vars (secrets via secretRef, plain values inline)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:46:39 +00:00
BaiFu af71244974
Merge pull request #428 from Ghostubborn/feat/i18n
feat(i18n): 添加多语言切换功能,支持中英文
2026-04-02 14:27:04 +08:00
ghostubborn f2404903d6 fix(i18n): validate Accept-Language header against registered locales 2026-04-02 14:20:15 +08:00
ghostubborn 24e9bee5be feat(i18n): replace all user-visible Chinese logger messages in zep_tools.py
These are shown to users via ConsoleLogger in the report page.
2026-04-01 17:46:39 +08:00
ghostubborn e79569ab4f feat(i18n): replace all user-visible Chinese in report_agent.py
Covers ReportLogger message fields and logger messages shown via ConsoleLogger.
2026-04-01 17:44:52 +08:00
666ghj e3350a919d fix(graph): enforce PascalCase for entity names and SCREAMING_SNAKE_CASE for edge names in ontology validation 2026-04-01 17:42:27 +08:00
ghostubborn 380e456d41 fix(i18n): replace hardcoded Chinese stage names in simulation prepare SSE 2026-04-01 17:31:00 +08:00
ghostubborn 0e55e4cf6b feat(i18n): replace remaining Chinese in config generator and profile generator
Also update simulation prompts to be locale-neutral for timezone/schedule.
2026-04-01 17:19:12 +08:00
ghostubborn 7c07237544 fix(i18n): pass locale to background threads via thread-local storage
Background threads (graph building, simulation prep, report generation,
profile generation) now inherit the requesting user's locale preference.
Previously these fell back to 'zh' because Flask request context was
unavailable in spawned threads.
2026-04-01 16:55:51 +08:00
ghostubborn 592ee52f59 feat(i18n): replace remaining hardcoded Chinese in progress callbacks 2026-04-01 16:53:29 +08:00
ghostubborn da2490ec31 fix(i18n): protect JSON field values from language instruction in config generator
Ensure poster_type stays PascalCase English and stance stays English enum
values regardless of language setting. Only natural language fields follow
the user's language preference.
2026-04-01 16:41:22 +08:00
ghostubborn 97aa58384e fix(i18n): ensure ontology names stay PascalCase regardless of language setting
The language instruction was causing LLM to change entity/relation naming
conventions. Now explicitly enforce PascalCase/UPPER_SNAKE_CASE for technical
identifiers while only applying language preference to description fields.
2026-04-01 16:40:17 +08:00
ghostubborn 9d43b77511 feat(i18n): replace hardcoded Chinese in backend SSE progress messages 2026-04-01 16:32:10 +08:00