10 KiB
Gap Analysis — i18n-simulation-config-generator-prompts
1. Current-State Investigation
Domain assets
- Target file:
backend/app/services/simulation_config_generator.py(~991 lines). - Three prompt blocks:
- Block 1 —
_generate_time_config(lines ~535–595). User prompt at lines 543–586 (f-string), system prompt at line 588,get_language_instruction()postfix at 589. - Block 2 —
_generate_event_config(lines ~646–717). User prompt at lines 676–703, system prompt at 705,get_language_instruction()postfix at 706 (already followed by an EnglishIMPORTANT:directive onposter_type). - Block 3 —
_generate_agent_configs_batch(lines ~813–906). User prompt at lines 833–867, system prompt at 869,get_language_instruction()postfix at 870 (already followed by an EnglishIMPORTANT:directive onstance).
- Block 1 —
- Indirect prompt content (interpolated via
{context_truncated}):_build_context(lines 381–407) emits Chinese section headings:## 模拟需求,## 实体信息 ({n}个),## 原始文档内容, truncation marker(文档已截断)._summarize_entities(lines 409–432) emits per-type headings### {entity_type} ({n}个)and overflow marker... 还有 {n} 个.
- Locale resolution:
backend/app/utils/locale.py(get_locale,get_language_instruction,t) resolves locale fromAccept-Languageheader in a request context, or thread-local in background threads.languages.jsonexposeszh,en,es,fr,pt,ru,de— all butzhalready use EnglishllmInstructionpostfixes.
Counts (verified)
| Region | Chinese chars |
|---|---|
| Block 1 user prompt | 417 |
| Block 1 system prompt | 38 |
| Block 2 user prompt | 173 |
| Block 2 system prompt | 27 |
| Block 3 user prompt | 207 |
| Block 3 system prompt | 36 |
_build_context body |
46 |
_summarize_entities body |
29 |
| File total (incl. logger, docstrings, comments) | 2415 |
The ticket's "~247 Chinese characters" undercounts the in-prompt total by ~3.6×. The actual prompt-string count is ~898; with context-builder headings (~75 more), the in-scope total is ~973. Logger lines, docstrings, and comments are out of scope (covered by #6/#7).
Conventions (extracted)
- Sister specs
i18n-ontology-generator-prompts(commit0806832) andi18n-oasis-profile-generator-prompts(commit9d1d29b) established the exact pattern: in-place translation; preserveget_language_instruction()call sites; preserve all interpolations and the trailing identifier-formatIMPORTANT:directives; do not touch logger, docstrings, comments, or any other file. - 4-space indent, snake_case, double quotes for strings,
f"""..."""for multi-line prompts. Existing Chinese-then-English mix is acceptable in comments/docstrings (steering-tech.md: "preserve both; do not translate one into the other unless asked"). - No linter/formatter — match surrounding style.
Integration surfaces
SimulationConfigGenerator.generate_config(...)is called fromservices/simulation_runner.pyand the simulation API blueprint. The returnedSimulationParameters.to_dict()is consumed by the OASIS subprocess viaservices/simulation_ipc.py. The JSON payload shape and field semantics must remain unchanged._build_contextand_summarize_entitiesare private helpers used only inside this file — translating their headings is local-only.- Locale-switching contract: when locale =
zh,get_language_instruction()returns请使用中文回答。; whenen,Please respond in English.— verified.
2. Requirement-to-Asset Map
| Requirement | Existing asset | Gap | Tag |
|---|---|---|---|
| R1 — Block 1 prompt EN | f-string at line 543, system_prompt at 588 | Translate text; preserve {context_truncated}, {max_agents_allowed}, JSON keys, field constraints, UTC+8 reference example |
Missing (translation) |
| R2 — Block 2 prompt EN | f-string at line 676, system_prompt at 705 | Translate text; preserve {simulation_requirement}, {context_truncated}, {type_info}, JSON keys, type-to-author examples, the IMPORTANT: poster_type ... PascalCase ... directive |
Missing (translation) |
| R3 — Block 3 prompt EN | f-string at line 833, system_prompt at 869 | Translate text; preserve {simulation_requirement} and the json.dumps(entity_list, ensure_ascii=False, indent=2) interpolation, JSON keys, per-entity-type heuristic ranges, the IMPORTANT: stance ... supportive/opposing/neutral/observer directive |
Missing (translation) |
| R4 — Locale switching preserved | get_language_instruction() calls at lines 589, 706, 870 |
None — keep call sites untouched | Constraint |
| R5 — Public API stable | Class/method/dataclass surface | None — text-only changes | Constraint |
| R6 — Default reasoning strings | _get_default_time_config line 608, _generate_event_config exception at line 716 |
Optional translation of two reasoning literals; non-empty contract preserved |
Optional gap |
| R7 — Context-builder headings EN | _build_context 393–406, _summarize_entities 422–430 |
Translate Chinese section headings inside f-strings; preserve interpolations | Missing (translation) |
| R8 — Step 3 parity | OASIS subprocess + simulation_ipc.py |
Verification only — the change should not alter SimulationParameters.to_dict() shape |
Constraint |
| R9 — Out-of-scope guardrails | logger calls (≥17 occurrences), docstrings, comments | None — leave untouched | Constraint |
Unknown / Research-needed
- R8 verification feasibility: Running an end-to-end OASIS simulation requires Neo4j, an LLM key, and a representative seed. In a sandboxed CI-like environment, this is not practical. Defer to a lightweight fixture-based check: (a) lint pass —
python -m py_compile, (b) zero-Chinese assertion on the three prompt strings viare.findall(r'[一-鿿]', ...), (c) shape parity by constructing a fakeentity_listand confirming the prompts render to the expected interpolation set without raising. Research item: confirm with the user whether a smoke-test run ofservices/simulation_runneris required for PR acceptance, or whether the pattern of #2/#3 (no end-to-end run, reviewer-trust) is acceptable here.
3. Implementation Approach Options
Option A — In-place translation (recommended)
What: Edit the six prompt string literals plus the two context-builder helper bodies directly in simulation_config_generator.py. No new files.
Trade-offs:
- ✅ Matches the precedent set by commits
0806832(issue #2) and9d1d29b(issue #3) — same file, same approach. Reviewer pattern recognition is the lowest possible. - ✅ Smallest possible diff, smallest possible blast radius.
- ✅ No new abstractions, no new files, no dependency churn.
- ❌ Translations are baked in — switching to
es/fr/pt/ru/destill relies on theget_language_instruction()postfix to bias the model. (This is also true under the current Chinese-base baseline; not a regression.)
Option B — Externalize prompts to /locales/
What: Move all six prompt strings to locales/en.json / locales/zh.json and use t('prompts.simConfig.timeConfig.user') etc. to look them up.
Trade-offs:
- ✅ Genuinely locale-agnostic prompts; richer non-
zh/ensupport. - ❌ Departs from the pattern set by #2 and #3 — those translations are in-line. Inconsistency between sister files.
- ❌ Significant new surface area in
/locales/JSON; brittle keys for f-string substitution (need to encode{topic},{n_agents},{json.dumps(...)}in JSON values). - ❌ Requires either templating-engine choice (Jinja, Python
str.format) or fragile string concatenation. - ❌ Out of scope per the ticket's "Out of scope: refactoring prompt structure or output JSON schema" guardrail (the structure is the prompt; moving it to JSON is a refactor).
Option C — Hybrid: in-place EN translation + introduce a thin prompt-loader for future extraction
What: Translate in-place now; also add a no-op _load_prompt(...) helper that just returns the literal, with a comment hinting at future externalization.
Trade-offs:
- ✅ Sets a future migration path.
- ❌ Adds an indirection that has no caller variance today — premature abstraction. Steering-tech.md explicitly discourages this style.
- ❌ Larger diff, more reviewer surface, no behavioural benefit over Option A.
4. Effort & Risk
- Effort: S (1–3 days). Six string literals plus two helper bodies; no schema, no API, no dependency changes. Sister-spec implementations completed in single commits (
0806832,9d1d29b). - Risk: Low. Translation is text-only; the JSON output contract, public API, and
get_language_instruction()mechanism are all preserved. The only behavioural risk is the LLM emitting different lexical choices for the same fields — this is the intended effect (English-flavoured output underAccept-Language: en).
5. Recommendation for Design Phase
-
Preferred approach: Option A. Match the sister-spec pattern (
0806832,9d1d29b) for reviewer continuity. -
Key decisions to lock in design:
- Wording style: Mirror the conversational/imperative style of
oasis_profile_generatorandontology_generatorpost-translation prompts — e.g."You are a social-media simulation expert. ..."rather than direct word-for-word ports of the Chinese. - Default-path
reasoningstrings (R6): Translate the two literals to English ("Default circadian-pattern config (1h per round)" and "Used default config"). Keep them locale-agnostic since they only fire on LLM failure, where locale is moot. This avoids a forever-Chinese leak into ageneration_reasoningjoined with English content. - Verification harness (R8): Use a lightweight fixture-only check (compile, regex for Chinese in prompt strings, render the prompts with stub data and assert interpolation completeness). No end-to-end OASIS run unless the reviewer requests it.
- Wording for the
IMPORTANT:directives: Keep the constraint semantics identical; allow light wording polish so the directive flows naturally after a now-English system prompt (e.g. drop theIMPORTANT:redundancy if the translated system prompt already encodes the constraint, or move the directive to be inline with the rest of the system prompt).
- Wording style: Mirror the conversational/imperative style of
-
Research items to carry: confirm verification scope (fixture vs. live) with implementation reviewer; if live is required, the sandboxed environment must have
LLM_API_KEY, Neo4j, and a seed file available — none of which are guaranteed in this run.