feat(wiki-compose): add Japanese UI and localized LLM output#985
Conversation
- Pass contentLocale from the client and resolve via Accept-Language on the API - Append locale instructions to Brief, research, structure, and draft prompts - Localize conflict-resolution copy and structure fallback outlines - Wire wikiCompose i18n keys through the Compose split-screen UI Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThreads content locale (ja|en) end-to-end: adds backend locale utilities and GraphContext field, resolves/persists locale in compose session routes, appends locale instructions to LLM system prompts, localizes frontend components and activity labels, and adds English/Japanese resource files and tests. ChangesWiki Compose Localization (ja/en)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces internationalization (i18n) support for the Wiki Compose feature, enabling localized outputs in Japanese ("ja") and English ("en") based on the user's UI language or Accept-Language headers. It introduces utility functions to resolve, normalize, and strip the content locale, integrates locale-specific system prompt instructions and fallback outlines, and translates frontend components using react-i18next. The code review identified three issues: an oversimplified Accept-Language header parser that ignores secondary preferences, potential type coercion bugs in stripContentLocaleFromGraphInput when handling falsy values, and an inconsistent default fallback locale in getGraphContext (defaulting to "en" instead of "ja").
| if (acceptLanguage) { | ||
| const primary = acceptLanguage.split(",")[0]?.trim().toLowerCase() ?? ""; | ||
| if (primary.startsWith("ja")) return "ja"; | ||
| if (primary.startsWith("en")) return "en"; | ||
| } |
There was a problem hiding this comment.
The current Accept-Language resolution only checks the very first language tag in the header. If a user has an unsupported primary language but a supported secondary language (e.g., Accept-Language: zh-CN,en-US;q=0.9), the parser will fail to match zh-CN and fall back to the default (ja), ignoring their preference for en.\n\nWe can improve this by splitting the header and checking each language tag in order of preference until a supported language is found.
if (acceptLanguage) {
const locales = acceptLanguage
.split(",")
.map((part) => part.split(";")[0]?.trim().toLowerCase() ?? "");
for (const locale of locales) {
if (locale.startsWith("ja")) return "ja";
if (locale.startsWith("en")) return "en";
}
}| export function stripContentLocaleFromGraphInput(raw: unknown): unknown { | ||
| if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw ?? {}; | ||
| const { contentLocale: _removed, ...rest } = raw as Record<string, unknown>; | ||
| return rest; | ||
| } |
There was a problem hiding this comment.
The current implementation of stripContentLocaleFromGraphInput uses !raw and raw ?? {} which silently coerces falsy values like null or undefined into empty objects {}.\n\nTo make this utility function more robust and prevent unexpected type coercions, we should return the input as-is if it is not a non-null object or array.
| export function stripContentLocaleFromGraphInput(raw: unknown): unknown { | |
| if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw ?? {}; | |
| const { contentLocale: _removed, ...rest } = raw as Record<string, unknown>; | |
| return rest; | |
| } | |
| export function stripContentLocaleFromGraphInput(raw: unknown): unknown { | |
| if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw; | |
| const { contentLocale: _removed, ...rest } = raw as Record<string, unknown>; | |
| return rest; | |
| } |
| const contentLocale = | ||
| normalizeComposeContentLocale(ctx.contentLocale) ?? | ||
| normalizeComposeContentLocale((ctx as { locale?: unknown }).locale) ?? | ||
| "en"; | ||
| return { ...(ctx as GraphContext), contentLocale }; |
There was a problem hiding this comment.
There is an inconsistency in the default fallback locale. In resolveComposeContentLocale and the route handlers, the fallback locale defaults to "ja". However, here in getGraphContext, it defaults to "en".\n\nTo ensure consistent behavior across the application when the locale cannot be resolved, we should use "ja" as the fallback here as well.
| const contentLocale = | |
| normalizeComposeContentLocale(ctx.contentLocale) ?? | |
| normalizeComposeContentLocale((ctx as { locale?: unknown }).locale) ?? | |
| "en"; | |
| return { ...(ctx as GraphContext), contentLocale }; | |
| const contentLocale = | |
| normalizeComposeContentLocale(ctx.contentLocale) ?? | |
| normalizeComposeContentLocale((ctx as { locale?: unknown }).locale) ?? | |
| "ja"; | |
| return { ...(ctx as GraphContext), contentLocale }; |
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 99f2d66691
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Resume relies on the checkpointer to fetch the suspended thread; production | ||
| // routes load `PostgresSaver` here, tests/smoke runs get `false`. | ||
| const checkpointer = await resolveCheckpointerForRun(); | ||
| const contentLocale = resolveComposeContentLocale(null, c.req.header("accept-language"), "ja"); |
There was a problem hiding this comment.
Persist contentLocale across resume calls
PATCH /compose-sessions/:id/resume recomputes contentLocale only from Accept-Language, so the language chosen on the initial POST /run (which comes from the app UI locale) is not preserved across interrupts. In the common case where a user sets the app to English but the browser header is Japanese, the run starts in English and then switches to Japanese after the first resume, breaking the new “UI language end-to-end” behavior. Use a session-stable source (e.g., persisted session metadata/checkpoint value or explicit resume payload) instead of recalculating from headers here.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/hooks/useWikiComposeSession.ts (1)
277-379:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winActivity detail text is still partially hardcoded in English.
labelis localized, but severaldetailvalues are still English literals (running,ok,chars,queries,sources, usage format), so Japanese UI can show mixed-language activity rows.🌐 Suggested direction
- detail: event.input ? "running" : undefined, + detail: event.input ? i18n.t("wikiCompose.activity.detail.running") : undefined, - detail: event.error ?? (event.outputLength ? `${event.outputLength} chars` : "ok"), + detail: + event.error ?? + (event.outputLength + ? i18n.t("wikiCompose.activity.detail.outputChars", { count: event.outputLength }) + : i18n.t("wikiCompose.activity.detail.ok")),Also move other detail templates (
queries,sources, usage line) towikiComposei18n keys in bothjaandenlocale files.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useWikiComposeSession.ts` around lines 277 - 379, The activity "detail" fields in useWikiComposeSession.ts are hardcoded English strings (e.g., the "running"/"ok" text in case "tool_start"/"tool_end", "chars" in "tool_end", the `${event.status} · ${event.queryCount} queries` in "research_iteration", `${event.sourceCount} sources · ${event.exitReason}` in "research_batch", the usage detail in "usage", and the compose_section count strings) — replace each literal with calls to i18n.t using new wikiCompose keys (e.g., wikiCompose.activity.running, wikiCompose.activity.ok, wikiCompose.activity.chars, wikiCompose.activity.queries, wikiCompose.activity.sources, wikiCompose.activity.usageLine, etc.) so all detail strings are localized; update the locale files (ja and en) with those keys and formats (use placeholders for numbers/status where needed) and ensure the code uses those placeholders (via i18n.t(..., { count: ..., status: ..., sourceCount: ... })) when constructing detail values in the cases referenced (cases "tool_start", "tool_end", "research_iteration", "research_batch", "compose_section", "usage"); leave appendActivity and reduceInterrupt usage unchanged.
🧹 Nitpick comments (10)
server/api/src/__tests__/agents/core/composeLocale.test.ts (1)
18-23: ⚡ Quick winAdd a regression case for mixed-language
Accept-Languageheaders.Please add a case like
fr-CA, en-US;q=0.9to ensure resolver picks the first supported locale in the list.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/api/src/__tests__/agents/core/composeLocale.test.ts` around lines 18 - 23, Add a regression test to verify mixed-language Accept-Language headers pick the first supported locale: in the test file add an expectation using resolveComposeContentLocale (the same helper under test) with an empty input object and the header string "fr-CA, en-US;q=0.9" and assert the result is "fr" so the resolver chooses the first supported locale in the list.src/components/wikiCompose/ActivitySection.tsx (1)
37-37: ⚡ Quick winAdd TSDoc comment for the exported component.
The
ActivitySectioncomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Activity timeline component showing agent operations in chronological order. + * エージェントの操作を時系列で表示するアクティビティタイムライン。 + */ export const ActivitySection: React.FC<ActivitySectionProps> = ({ activity, isStreaming }) => {As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/ActivitySection.tsx` at line 37, Add a TSDoc comment immediately above the exported ActivitySection declaration describing the component, its props and their types; reference ActivitySection and ActivitySectionProps and document the activity and isStreaming props (what they represent and expected types/behavior), include a short example or usage note if helpful, and ensure the comment is formatted as a /** ... */ TSDoc block placed directly before the line "export const ActivitySection: React.FC<ActivitySectionProps> = ({ activity, isStreaming }) => {".src/components/wikiCompose/DialogueSection.tsx (1)
59-59: ⚡ Quick winAdd TSDoc comment for the exported component.
The
DialogueSectioncomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Container for Brief/Structure/Draft dialogue UIs based on current phase. + * フェーズに応じてBrief/Structure/Draftの対話UIを出し分けるコンテナ。 + */ export const DialogueSection: React.FC<DialogueSectionProps> = ({As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/DialogueSection.tsx` at line 59, Add a TSDoc comment immediately above the exported React component declaration for DialogueSection that documents the component purpose and its props (DialogueSectionProps); include a short description, `@param` for the props object (or individual props if preferred), and an `@returns` tag describing the JSX.Element. Place the comment directly above the line "export const DialogueSection: React.FC<DialogueSectionProps> = ({", so it documents the exported DialogueSection and its props type DialogueSectionProps.src/components/wikiCompose/ResearchSection.tsx (1)
36-36: ⚡ Quick winAdd TSDoc comment for the exported component.
The
ResearchSectioncomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Research source review panel for approving/rejecting sources. + * ソースの採用・却下を行う調査レビューパネル。 + */ export const ResearchSection: React.FC<ResearchSectionProps> = ({As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/ResearchSection.tsx` at line 36, Add a TSDoc comment immediately above the exported ResearchSection declaration describing the component, its props (ResearchSectionProps) and the return value; place the comment directly before "export const ResearchSection: React.FC<ResearchSectionProps> = ({". The TSDoc should include a short one-line summary, an `@param` block for the props (or individual prop tags if preferred) and an `@returns` tag indicating it returns a React element. Ensure the comment follows TSDoc/JSDoc format (/** ... */).src/components/wikiCompose/OutlineEditor.tsx (1)
32-32: ⚡ Quick winAdd TSDoc comment for the exported component.
The
OutlineEditorcomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Editable outline list for the Structure phase with reordering and depth controls. + * Structure フェーズ用の編集可能なアウトラインリスト(並び替え・深度制御付き)。 + */ export const OutlineEditor: React.FC<OutlineEditorProps> = ({As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/OutlineEditor.tsx` at line 32, Add a TSDoc comment immediately above the exported component declaration for OutlineEditor describing its purpose and props; document the component name (OutlineEditor) and its props type (OutlineEditorProps), include a short summary line and `@param` for the props (or `@remarks` if needed) and `@returns` description, and ensure the comment is placed directly above "export const OutlineEditor: React.FC<OutlineEditorProps> = ({".src/components/wikiCompose/BriefQuestionCard.tsx (1)
31-31: ⚡ Quick winAdd TSDoc comment for the exported component.
The
BriefQuestionCardcomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Brief question card with optional answer chips and free-text input. + * チップ式選択肢とフリーテキスト入力を持つBrief質問カード。 + */ export const BriefQuestionCard: React.FC<BriefQuestionCardProps> = ({As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/BriefQuestionCard.tsx` at line 31, Add a TSDoc comment immediately above the exported component declaration for BriefQuestionCard describing what the component renders and its purpose, document the BriefQuestionCardProps prop with `@param` along with any important prop fields (e.g., callbacks or required values), and include an `@returns` describing the JSX element; place the comment directly before the line "export const BriefQuestionCard: React.FC<BriefQuestionCardProps> = ({".src/components/wikiCompose/EditorPane.tsx (1)
29-29: ⚡ Quick winAdd TSDoc comment for the exported component.
The
EditorPanecomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Left pane editor showing streaming draft content and completed markdown. + * ストリーミング中のドラフト内容と完成版Markdownを表示する左ペインエディタ。 + */ export const EditorPane: React.FC<EditorPaneProps> = ({As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/EditorPane.tsx` at line 29, Add a TSDoc comment immediately above the exported declaration "export const EditorPane: React.FC<EditorPaneProps> = ({..." that summarizes the component's purpose, documents the props via `@param` for "EditorPaneProps" (or list key props if they are individual props), and includes an `@returns` tag describing the rendered JSX (e.g., React element). Ensure the comment sits directly before the EditorPane declaration and follows TSDoc format so tooling and lint rules recognize it.src/components/wikiCompose/PhaseStepper.tsx (1)
26-26: ⚡ Quick winAdd TSDoc comment for the exported component.
The
PhaseSteppercomponent is exported but lacks a TSDoc comment immediately before its declaration. As per coding guidelines, all exported functions, types, and interfaces require TSDoc/JSDoc comments.📝 Proposed addition
+/** + * Progress indicator showing the five Wiki Compose phases. + * Wiki Composeの5段階フェーズを表示する進捗インジケーター。 + */ export const PhaseStepper: React.FC<PhaseStepperProps> = ({ phase }) => {As per coding guidelines: "Include TSDoc/JSDoc comments for all exported functions, types, and interfaces".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/wikiCompose/PhaseStepper.tsx` at line 26, Add a TSDoc comment immediately above the exported React component declaration for PhaseStepper describing its purpose and parameters; include a one-line summary, a `@param` tag for the phase prop referencing PhaseStepperProps (or describe the phase field) and a `@returns` tag noting it renders the stepper UI. Place the comment directly above "export const PhaseStepper: React.FC<PhaseStepperProps> = ({ phase }) => {" so it documents the exported symbol PhaseStepper and its props.src/pages/WikiComposePage.tsx (1)
153-157: ⚡ Quick winRemove misleading
as constassertion.The
as constassertion on line 154 doesn't provide type narrowing sincesession.phaseis a runtime value. TypeScript cannot create a template literal type from non-literal interpolations, so this assertion is ineffective and may create false confidence.♻️ Simplified version without the assertion
const phaseLabel = (() => { - const key = `wikiCompose.phaseDisplay.${session.phase}` as const; + const key = `wikiCompose.phaseDisplay.${session.phase}`; const translated = t(key); return translated === key ? session.phase : translated; })();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/WikiComposePage.tsx` around lines 153 - 157, The `as const` assertion on the template key is misleading because `session.phase` is a runtime value; remove the `as const` so the `key` is a plain string (e.g., change the `key` declaration in the `phaseLabel` IIFE to a string without `as const`), keep using `t(key)` and the fallback check `translated === key ? session.phase : translated` to preserve behavior; locate the `phaseLabel` block and update the `key` variable (and any related type annotations) accordingly.src/hooks/useWikiComposeSession.test.ts (1)
30-32: ⚡ Quick winMake the locale resolver mock configurable per test.
Hardcoding
"ja"here means this integration suite never verifies the"en"payload path inrunSessioninput.🧪 Proposed test refactor
const mocks = vi.hoisted(() => ({ createSession: vi.fn(), getSession: vi.fn(), runSession: vi.fn(), resumeSession: vi.fn(), cancelSession: vi.fn(), + resolveComposeContentLocale: vi.fn(() => "ja" as const), })); vi.mock("`@/lib/wikiCompose/resolveComposeContentLocale`", () => ({ - resolveComposeContentLocale: () => "ja" as const, + resolveComposeContentLocale: mocks.resolveComposeContentLocale, }));Then add one test that sets
mocks.resolveComposeContentLocale.mockReturnValue("en")and assertsbody.contentLocale === "en".As per coding guidelines
**/*.{test,spec}.{ts,tsx,js,jsx}: Tests serve as a source of truth for specifications alongside implementation code TSDoc/JSDoc.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useWikiComposeSession.test.ts` around lines 30 - 32, Replace the hardcoded module mock so tests can override the locale: change the mock of "`@/lib/wikiCompose/resolveComposeContentLocale`" to export resolveComposeContentLocale as a vi.fn(() => "ja") (i.e. vi.mock(..., () => ({ resolveComposeContentLocale: vi.fn(() => "ja") }))), then in individual tests call mocks.resolveComposeContentLocale.mockReturnValue("en") (or "ja") before invoking runSession and assert body.contentLocale === "en" in the new test; reference the mocked symbol resolveComposeContentLocale and the runSession assertion to locate where to adjust the tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/api/src/agents/core/composeLocale.ts`:
- Line 86: The JSDoc comment "Default outline rows when structure LLM fails
(locale-specific headings)." is English-only; update the JSDoc in
composeLocale.ts by adding the Japanese equivalent alongside the English text
(e.g., add a Japanese sentence like 「構造LLMが失敗した場合のデフォルトのアウトライン行(ロケール別見出し)。」) so
the comment above the related constant/function (the JSDoc that describes
default outline rows) contains both Japanese and English versions to match
project guidelines.
- Around line 31-35: The current logic in composeLocale uses only the first
token (acceptLanguage -> primary) so headers like "fr-CA, en-US;q=0.9" get
ignored; update the code that handles acceptLanguage to parse the full
comma-separated list, parse each language-range's optional q value, sort or
select by descending q (default q=1 when missing), then iterate the ordered
ranges and return "ja" if any range startsWith("ja") or "en" if any
startsWith("en"); use the existing acceptLanguage variable and replace the
primary-check block with this full-list parsing logic and fallbacks.
In `@server/api/src/routes/composeSessions.ts`:
- Line 122: The JSDoc for the function that builds a GraphContext (the comment
starting "/** Build {`@link` GraphContext} for a compose session run / projection.
*/") is only in English; add a Japanese counterpart immediately below or above
the English sentence so both languages appear in the same JSDoc block (e.g.,
"Compose セッションの実行/プロジェクションのための {`@link` GraphContext} を構築します。"), keeping the
existing {`@link` GraphContext} reference and any param/return tags intact and
mirrored in Japanese as needed to follow repo bilingual doc convention.
In `@src/hooks/useWikiComposeSession.ts`:
- Around line 229-235: The new helper comments for withContentLocale and
phaseDisplayLabel are only in English; update the documentation comments to
include both Japanese and English per the repo guideline. Edit the JSDoc/comment
above withContentLocale and phaseDisplayLabel (and any mention of
resolveComposeContentLocale if referenced) to add concise Japanese translations
alongside the existing English text so each helper has bilingual comments.
In `@src/lib/wikiCompose/resolveComposeContentLocale.ts`:
- Around line 7-10: Add bilingual (Japanese and English) TSDoc comments for the
exported ComposeContentLocale type and the resolveComposeContentLocale function:
for ComposeContentLocale, document the purpose and allowed literal values ("ja"
| "en") in both languages; for resolveComposeContentLocale, add a bilingual
description, include `@returns` describing that it returns "ja" or "en" derived
from the active i18next language, and any remarks about fallback behavior if
applicable; attach these comments directly above the exported type and function
declarations so they satisfy the repository’s documentation guidelines.
In `@src/pages/WikiComposePage.tsx`:
- Line 43: Convert the existing inline bilingual comments for the exported React
component into JSDoc/TSDoc style by adding a /** ... */ comment block
immediately above the WikiComposePage declaration; document the component
purpose, any props (none in this case) and its return value, and include
`@component` and `@returns` tags (or equivalent) so the exported symbol
WikiComposePage has a proper JSDoc header that satisfies the coding guidelines
and linter rules.
---
Outside diff comments:
In `@src/hooks/useWikiComposeSession.ts`:
- Around line 277-379: The activity "detail" fields in useWikiComposeSession.ts
are hardcoded English strings (e.g., the "running"/"ok" text in case
"tool_start"/"tool_end", "chars" in "tool_end", the `${event.status} ·
${event.queryCount} queries` in "research_iteration", `${event.sourceCount}
sources · ${event.exitReason}` in "research_batch", the usage detail in "usage",
and the compose_section count strings) — replace each literal with calls to
i18n.t using new wikiCompose keys (e.g., wikiCompose.activity.running,
wikiCompose.activity.ok, wikiCompose.activity.chars,
wikiCompose.activity.queries, wikiCompose.activity.sources,
wikiCompose.activity.usageLine, etc.) so all detail strings are localized;
update the locale files (ja and en) with those keys and formats (use
placeholders for numbers/status where needed) and ensure the code uses those
placeholders (via i18n.t(..., { count: ..., status: ..., sourceCount: ... }))
when constructing detail values in the cases referenced (cases "tool_start",
"tool_end", "research_iteration", "research_batch", "compose_section", "usage");
leave appendActivity and reduceInterrupt usage unchanged.
---
Nitpick comments:
In `@server/api/src/__tests__/agents/core/composeLocale.test.ts`:
- Around line 18-23: Add a regression test to verify mixed-language
Accept-Language headers pick the first supported locale: in the test file add an
expectation using resolveComposeContentLocale (the same helper under test) with
an empty input object and the header string "fr-CA, en-US;q=0.9" and assert the
result is "fr" so the resolver chooses the first supported locale in the list.
In `@src/components/wikiCompose/ActivitySection.tsx`:
- Line 37: Add a TSDoc comment immediately above the exported ActivitySection
declaration describing the component, its props and their types; reference
ActivitySection and ActivitySectionProps and document the activity and
isStreaming props (what they represent and expected types/behavior), include a
short example or usage note if helpful, and ensure the comment is formatted as a
/** ... */ TSDoc block placed directly before the line "export const
ActivitySection: React.FC<ActivitySectionProps> = ({ activity, isStreaming }) =>
{".
In `@src/components/wikiCompose/BriefQuestionCard.tsx`:
- Line 31: Add a TSDoc comment immediately above the exported component
declaration for BriefQuestionCard describing what the component renders and its
purpose, document the BriefQuestionCardProps prop with `@param` along with any
important prop fields (e.g., callbacks or required values), and include an
`@returns` describing the JSX element; place the comment directly before the line
"export const BriefQuestionCard: React.FC<BriefQuestionCardProps> = ({".
In `@src/components/wikiCompose/DialogueSection.tsx`:
- Line 59: Add a TSDoc comment immediately above the exported React component
declaration for DialogueSection that documents the component purpose and its
props (DialogueSectionProps); include a short description, `@param` for the props
object (or individual props if preferred), and an `@returns` tag describing the
JSX.Element. Place the comment directly above the line "export const
DialogueSection: React.FC<DialogueSectionProps> = ({", so it documents the
exported DialogueSection and its props type DialogueSectionProps.
In `@src/components/wikiCompose/EditorPane.tsx`:
- Line 29: Add a TSDoc comment immediately above the exported declaration
"export const EditorPane: React.FC<EditorPaneProps> = ({..." that summarizes the
component's purpose, documents the props via `@param` for "EditorPaneProps" (or
list key props if they are individual props), and includes an `@returns` tag
describing the rendered JSX (e.g., React element). Ensure the comment sits
directly before the EditorPane declaration and follows TSDoc format so tooling
and lint rules recognize it.
In `@src/components/wikiCompose/OutlineEditor.tsx`:
- Line 32: Add a TSDoc comment immediately above the exported component
declaration for OutlineEditor describing its purpose and props; document the
component name (OutlineEditor) and its props type (OutlineEditorProps), include
a short summary line and `@param` for the props (or `@remarks` if needed) and
`@returns` description, and ensure the comment is placed directly above "export
const OutlineEditor: React.FC<OutlineEditorProps> = ({".
In `@src/components/wikiCompose/PhaseStepper.tsx`:
- Line 26: Add a TSDoc comment immediately above the exported React component
declaration for PhaseStepper describing its purpose and parameters; include a
one-line summary, a `@param` tag for the phase prop referencing PhaseStepperProps
(or describe the phase field) and a `@returns` tag noting it renders the stepper
UI. Place the comment directly above "export const PhaseStepper:
React.FC<PhaseStepperProps> = ({ phase }) => {" so it documents the exported
symbol PhaseStepper and its props.
In `@src/components/wikiCompose/ResearchSection.tsx`:
- Line 36: Add a TSDoc comment immediately above the exported ResearchSection
declaration describing the component, its props (ResearchSectionProps) and the
return value; place the comment directly before "export const ResearchSection:
React.FC<ResearchSectionProps> = ({". The TSDoc should include a short one-line
summary, an `@param` block for the props (or individual prop tags if preferred)
and an `@returns` tag indicating it returns a React element. Ensure the comment
follows TSDoc/JSDoc format (/** ... */).
In `@src/hooks/useWikiComposeSession.test.ts`:
- Around line 30-32: Replace the hardcoded module mock so tests can override the
locale: change the mock of "`@/lib/wikiCompose/resolveComposeContentLocale`" to
export resolveComposeContentLocale as a vi.fn(() => "ja") (i.e. vi.mock(..., ()
=> ({ resolveComposeContentLocale: vi.fn(() => "ja") }))), then in individual
tests call mocks.resolveComposeContentLocale.mockReturnValue("en") (or "ja")
before invoking runSession and assert body.contentLocale === "en" in the new
test; reference the mocked symbol resolveComposeContentLocale and the runSession
assertion to locate where to adjust the tests.
In `@src/pages/WikiComposePage.tsx`:
- Around line 153-157: The `as const` assertion on the template key is
misleading because `session.phase` is a runtime value; remove the `as const` so
the `key` is a plain string (e.g., change the `key` declaration in the
`phaseLabel` IIFE to a string without `as const`), keep using `t(key)` and the
fallback check `translated === key ? session.phase : translated` to preserve
behavior; locate the `phaseLabel` block and update the `key` variable (and any
related type annotations) accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 02652e6a-9acd-4528-aab7-512f0925aa52
📒 Files selected for processing (27)
server/api/src/__tests__/agents/core/composeLocale.test.tsserver/api/src/agents/core/composeLocale.tsserver/api/src/agents/core/types/graphContext.tsserver/api/src/agents/graphs/wikiCompose/nodes/briefDialogue.tsserver/api/src/agents/graphs/wikiCompose/nodes/conflictResolution.tsserver/api/src/agents/graphs/wikiCompose/nodes/draftSections.tsserver/api/src/agents/graphs/wikiCompose/nodes/structureDialogue.tsserver/api/src/agents/subgraphs/research/nodes/evaluateSufficiency.tsserver/api/src/agents/subgraphs/research/nodes/planQueries.tsserver/api/src/agents/subgraphs/research/nodes/refineQueries.tsserver/api/src/agents/subgraphs/research/nodes/shared/getGraphContext.tsserver/api/src/routes/composeSessions.tssrc/components/wikiCompose/ActivitySection.tsxsrc/components/wikiCompose/BriefQuestionCard.tsxsrc/components/wikiCompose/ConflictResolutionSection.tsxsrc/components/wikiCompose/DialogueSection.tsxsrc/components/wikiCompose/EditorPane.tsxsrc/components/wikiCompose/OutlineEditor.tsxsrc/components/wikiCompose/PhaseStepper.tsxsrc/components/wikiCompose/ResearchSection.tsxsrc/hooks/useWikiComposeSession.test.tssrc/hooks/useWikiComposeSession.tssrc/i18n/locales/en/wikiCompose.jsonsrc/i18n/locales/ja/wikiCompose.jsonsrc/lib/wikiCompose/resolveComposeContentLocale.test.tssrc/lib/wikiCompose/resolveComposeContentLocale.tssrc/pages/WikiComposePage.tsx
| return undefined; | ||
| } | ||
|
|
||
| /** Build {@link GraphContext} for a compose session run / projection. */ |
There was a problem hiding this comment.
Make this new function doc bilingual (EN + JA).
This added JSDoc currently has only English; please add the Japanese counterpart to keep docs consistent with repo conventions.
As per coding guidelines: “Include both Japanese and English comments/documentation in code and documentation files to maintain project tone consistency”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/api/src/routes/composeSessions.ts` at line 122, The JSDoc for the
function that builds a GraphContext (the comment starting "/** Build {`@link`
GraphContext} for a compose session run / projection. */") is only in English;
add a Japanese counterpart immediately below or above the English sentence so
both languages appear in the same JSDoc block (e.g., "Compose
セッションの実行/プロジェクションのための {`@link` GraphContext} を構築します。"), keeping the existing
{`@link` GraphContext} reference and any param/return tags intact and mirrored in
Japanese as needed to follow repo bilingual doc convention.
| /** Merge graph run input with the active UI content locale. */ | ||
| function withContentLocale(input?: Record<string, unknown>): Record<string, unknown> { | ||
| return { ...(input ?? {}), contentLocale: resolveComposeContentLocale() }; | ||
| } | ||
|
|
||
| /** Human-readable phase label for activity log entries. */ | ||
| function phaseDisplayLabel(phase: string): string { |
There was a problem hiding this comment.
Keep newly added helper comments bilingual.
The newly added helper docs are English-only; this diverges from the project’s bilingual documentation rule.
✍️ Proposed fix
-/** Merge graph run input with the active UI content locale. */
+/**
+ * Merge graph run input with the active UI content locale.
+ * graph 実行入力に現在の UI コンテンツロケールをマージする。
+ */
function withContentLocale(input?: Record<string, unknown>): Record<string, unknown> {
return { ...(input ?? {}), contentLocale: resolveComposeContentLocale() };
}
-/** Human-readable phase label for activity log entries. */
+/**
+ * Human-readable phase label for activity log entries.
+ * アクティビティログ用の可読フェーズラベルを返す。
+ */
function phaseDisplayLabel(phase: string): string {As per coding guidelines **/*.{ts,tsx,js,jsx,md}: Include both Japanese and English comments/documentation in code and documentation files.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** Merge graph run input with the active UI content locale. */ | |
| function withContentLocale(input?: Record<string, unknown>): Record<string, unknown> { | |
| return { ...(input ?? {}), contentLocale: resolveComposeContentLocale() }; | |
| } | |
| /** Human-readable phase label for activity log entries. */ | |
| function phaseDisplayLabel(phase: string): string { | |
| /** | |
| * Merge graph run input with the active UI content locale. | |
| * graph 実行入力に現在の UI コンテンツロケールをマージする。 | |
| */ | |
| function withContentLocale(input?: Record<string, unknown>): Record<string, unknown> { | |
| return { ...(input ?? {}), contentLocale: resolveComposeContentLocale() }; | |
| } | |
| /** | |
| * Human-readable phase label for activity log entries. | |
| * アクティビティログ用の可読フェーズラベルを返す。 | |
| */ | |
| function phaseDisplayLabel(phase: string): string { |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/hooks/useWikiComposeSession.ts` around lines 229 - 235, The new helper
comments for withContentLocale and phaseDisplayLabel are only in English; update
the documentation comments to include both Japanese and English per the repo
guideline. Edit the JSDoc/comment above withContentLocale and phaseDisplayLabel
(and any mention of resolveComposeContentLocale if referenced) to add concise
Japanese translations alongside the existing English text so each helper has
bilingual comments.
| @@ -40,6 +41,7 @@ function indexById(items: DraftedSection[]): Record<string, DraftedSection> { | |||
|
|
|||
| /** Root page for `/notes/:noteId/:pageId/compose[/:sessionId]`. */ | |||
| const WikiComposePage: React.FC = () => { | |||
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Convert component documentation to JSDoc format.
The component has excellent bilingual inline comments but they should be in JSDoc format to comply with the coding guidelines. As per coding guidelines, all exported functions, types, and interfaces must include TSDoc/JSDoc comments.
📝 Convert to JSDoc format
-/**
- * `WikiComposePage` — Wiki Compose split-screen UI (`#950`).
- *
- * `/notes/:noteId/:pageId/compose` (および `compose/:sessionId`) のルート要素。
- * 左ペイン = `EditorPane` (タイトル + 進捗中の本文プレビュー)、右ペイン =
- * `ComposePanel` (PhaseStepper + Dialogue + Research + Activity)。
- * モバイルでは縦分割、デスクトップでは横分割で表示する。Compose 完了 / 中断
- * 時はノートページに戻れる。
- *
- * Compose UI shell. The page reads the `useWikiComposeSession` hook for state
- * and routes user submissions back through the hook's mutator methods.
- */
+/**
+ * Wiki Compose split-screen UI.
+ * Wiki Compose の分割画面 UI。
+ *
+ * Root component for `/notes/:noteId/:pageId/compose` (and `compose/:sessionId`) routes.
+ * `/notes/:noteId/:pageId/compose` (および `compose/:sessionId`) のルート要素。
+ *
+ * Layout:
+ * - Left pane: `EditorPane` (title + live draft preview)
+ * - Right pane: `ComposePanel` (PhaseStepper + Dialogue + Research + Activity)
+ * - Mobile: vertical split; Desktop: horizontal split
+ *
+ * レイアウト:
+ * - 左ペイン: `EditorPane` (タイトル + 進捗中の本文プレビュー)
+ * - 右ペイン: `ComposePanel` (PhaseStepper + Dialogue + Research + Activity)
+ * - モバイル: 縦分割、デスクトップ: 横分割
+ *
+ * State management via `useWikiComposeSession` hook; user submissions route through hook mutators.
+ * Compose 完了 / 中断時はノートページに戻る。
+ *
+ * `@returns` The Wiki Compose page component
+ */
const WikiComposePage: React.FC = () => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/WikiComposePage.tsx` at line 43, Convert the existing inline
bilingual comments for the exported React component into JSDoc/TSDoc style by
adding a /** ... */ comment block immediately above the WikiComposePage
declaration; document the component purpose, any props (none in this case) and
its return value, and include `@component` and `@returns` tags (or equivalent) so
the exported symbol WikiComposePage has a proper JSDoc header that satisfies the
coding guidelines and linter rules.
- Store contentLocale in session metadata on first run; reuse on resume/GET - Parse Accept-Language with q-values via invitationService helper - Default getGraphContext fallback to ja; preserve null/undefined in strip helper - Add contentLocale to GraphContext test fixtures and ingest graph routes Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/api/src/routes/composeSessions.ts`:
- Around line 375-387: The DB metadata write after claiming status "running"
(the block that calls readContentLocaleFromSessionMetadata and then
db.update(wikiComposeSessions).set({...})) can throw and abort before SSE
execution/persistence cleanup runs, leaving the session stuck; wrap that update
in a try/catch around the call to db.update(wikiComposeSessions).set(...)
(referencing wikiComposeSessions, id, pageId, contentLocale and
readContentLocaleFromSessionMetadata) and on error log detailed context (id,
pageId, error) but do not rethrow — ensure execution continues so the SSE
cleanup and normal persistence/cleanup paths still run; optionally add a
lightweight retry or enqueue a background retry for the metadata update.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 780b1d82-d1ef-4629-8188-fbd8ee8abb6c
📒 Files selected for processing (17)
server/api/src/__tests__/agents/core/composeLocale.test.tsserver/api/src/__tests__/agents/graphs/ingest/ingestPlannerGraph.test.tsserver/api/src/__tests__/agents/graphs/ingest/planIngestModel.test.tsserver/api/src/__tests__/agents/graphs/wikiCompose/wikiComposeGraph.test.tsserver/api/src/__tests__/agents/graphs/wikiMaintenance/wikiMaintenanceGraph.test.tsserver/api/src/__tests__/agents/runner/graphRunner.test.tsserver/api/src/__tests__/agents/subgraphs/research/nodes/planQueries.test.tsserver/api/src/__tests__/agents/subgraphs/research/researchGraph.interrupt.test.tsserver/api/src/__tests__/agents/subgraphs/research/researchGraph.loop.test.tsserver/api/src/__tests__/agents/subgraphs/research/researchGraph.modelGuard.test.tsserver/api/src/__tests__/agents/subgraphs/research/researchGraph.resume.test.tsserver/api/src/__tests__/agents/subgraphs/research/tools/webSearch.test.tsserver/api/src/__tests__/agents/subgraphs/research/tools/wikiSearch.test.tsserver/api/src/agents/core/composeLocale.tsserver/api/src/agents/subgraphs/research/nodes/shared/getGraphContext.tsserver/api/src/routes/composeSessions.tsserver/api/src/routes/ingest.ts
✅ Files skipped from review due to trivial changes (5)
- server/api/src/tests/agents/subgraphs/research/researchGraph.interrupt.test.ts
- server/api/src/tests/agents/subgraphs/research/researchGraph.loop.test.ts
- server/api/src/tests/agents/subgraphs/research/nodes/planQueries.test.ts
- server/api/src/tests/agents/subgraphs/research/researchGraph.modelGuard.test.ts
- server/api/src/tests/agents/core/composeLocale.test.ts
Combine running status and metadata locale into one update so a failed metadata write cannot strand the session in running without locale data. Co-authored-by: Akimasa Sugai <otomatty@users.noreply.github.com>
Summary
Wiki Compose now follows the app UI language (Japanese or English) end to end:
wikiComposei18n keys (ja/en).contentLocaleon the first graph run; the API also falls back toAccept-Language. Brief questions, research rationales, outline headings/intents, section drafts, and conflict-resolution copy are instructed to match that locale.Changes
server/api/src/agents/core/composeLocale.tsandGraphContext.contentLocalecontentLocalefrom LangGraph inputsrc/i18n/locales/{ja,en}/wikiCompose.jsonand wired components +useWikiComposeSessionTesting
bun test server/api/src/__tests__/agents/core/composeLocale.test.tsbunx vitest run src/hooks/useWikiComposeSession.test.ts src/lib/wikiCompose/resolveComposeContentLocale.test.tsSummary by CodeRabbit
New Features
Tests