Backend:
- Add /api/agent-group/categorize endpoint — AI groups agents by role
- Add /api/agent-group/filter endpoint — filter by selected groups
- Groups with default_enabled=false (advertiser, brand) are unchecked
Frontend:
- Add agent groups section in Step2EnvSetup.vue
- 'Auto-categorize' button triggers AI grouping
- Show groups with checkboxes (enabled groups checked, disabled unchecked)
- Auto-remove unchecked agents when proceeding to Step 3
- Show selected count summary
- Add marketing metadata to 'Not allowed' list in ontology prompt
- Strengthen exclude_self filter instruction
- Add exclude_rules support from template filter rules
- Update business_ad template with more excluded types
- OntologyGenerator.generate() now accepts template_filter_rules parameter
- When template_id is provided, API loads filter rules from templates.json
- Filter rules injected into ontology system prompt:
- exclude_self: don't create entity for the business/brand that uploaded data
- exclude_types: don't create specific entity types
- focus: guide LLM to focus on specific entity categories
- API endpoint accepts template_id in form data
Root cause found in container: camel-ai v0.2.78 openai_model.py L117 reads
os.environ.get('OPENAI_API_BASE_URL') — NOT OPENAI_BASE_URL.
Fix: Set BOTH env vars (OPENAI_BASE_URL for OpenAI SDK + OPENAI_API_BASE_URL for camel-ai).
Keep model_config_dict={} empty so nothing spreads to create().
Also fix Step 2 Thai truncation: \w regex doesn't match Thai tone marks (Mn category).
Use explicit Unicode range \u0E00-\u0E7F instead.
1. Restore OPENAI_API_KEY/OPENAI_BASE_URL env vars for camel-ai factory check
(keep api_key/base_url in model_config_dict for client constructor)
2. Add Thai-supporting font-family to .profile-realname
(JetBrains Mono doesn't render Thai diacritics)
3. Keep model_config_dict with api_key and base_url for camel-ai client
camel-ai v0.2.78 reads OPENAI_API_KEY from env and auto-passes it to
chat.completions.create() which doesn't accept it (TypeError).
Fix: pass api_key and base_url through model_config_dict so camel-ai
extracts them for the OpenAI client constructor only.
camel-ai's OpenAI model reads OPENAI_BASE_URL, not OPENAI_API_BASE_URL.
This caused all simulation LLM calls to go to api.openai.com instead of
the configured provider (DeepSeek, Xiaomi Mimo, etc), resulting in 401.
- Time config: translate all Chinese instructions and field descriptions
- Event config: translate hot topics/narrative direction instructions
- Agent config: translate entity type descriptions and field labels
- Profile generator: translate all persona prompt fields and instructions
- Country field: changed from 'use Chinese' to 'use English'
- simulation_config_generator.py: translate all LLM prompts and system messages
- oasis_profile_generator.py: translate profile generation prompts
Ensures get_language_instruction() controls output language instead of
being overridden by Chinese prompt context.
- Interview prompt prefix: Chinese -> English
- Sub-query decomposition: Chinese -> English
- Agent selection: Chinese -> English
- Interview questions: Chinese -> English
- Interview summary: Chinese -> English
- Error messages: Chinese -> English
- to_text() labels: Chinese -> English
This ensures get_language_instruction() actually controls output language
instead of being overridden by Chinese prompt context.
- Add return type annotation (list[str]) to Config.validate()
- Add type annotations (msg: str, -> None) to logger convenience functions
- Add FileParser.is_supported() classmethod for checking file format support
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.
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.
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.