Improve ghostwriter output language guidance (#248)

This commit is contained in:
Shaheer Sarfaraz 2026-03-10 14:52:19 +00:00 committed by GitHub
parent 8c952a4011
commit ee6f889094
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 0 deletions

View File

@ -27,6 +27,7 @@ Typical use cases:
- cover letter and outreach drafts
- interview prep tied to the job description
- rephrasing with tone constraints
- multilingual drafting when you want replies in a specific language
## How to use it
@ -44,6 +45,10 @@ Global settings affecting generations:
- `Constraints`
- `Do-not-use terms`
Ghostwriter follows the output language you request in your prompt. For example, `Ecris en français` should produce a French reply.
If you want a persistent default language, put it in `Constraints`, for example: `Always respond in French.`
`Do-not-use terms` are passed as guidance in the prompt. They are not enforced by a hard post-generation filter, so the model should avoid them but may still use them occasionally.
Defaults:
@ -80,6 +85,7 @@ Compatibility thread endpoints remain, but UI behavior is one thread per job.
- Check model/provider configuration in Settings.
- Tighten prompts with explicit output intent (for example, "3 bullet points for recruiter outreach").
- If you need a non-English response every time, add that language requirement to `Constraints`.
### Missing context in answers

View File

@ -73,6 +73,7 @@ Settings gives you runtime overrides for the key parts of discovery, scoring, ta
- Constraints
- Do-not-use terms
- These settings apply to Ghostwriter and resume tailoring
- `Constraints` can also set a default output language, for example `Always respond in French.`
- Do-not-use terms are model guidance, not a guaranteed output filter
### Reactive Resume

View File

@ -80,6 +80,15 @@ describe("buildJobChatPromptContext", () => {
});
expect(context.systemPrompt).toContain("Writing style tone: direct.");
expect(context.systemPrompt).toContain("Writing style formality: high.");
expect(context.systemPrompt).toContain(
"Follow the user's requested output language exactly when they specify one.",
);
expect(context.systemPrompt).toContain(
"If the global writing constraints specify an output language, follow that when the user has not requested a different language.",
);
expect(context.systemPrompt).toContain(
"If no output language is specified elsewhere, reply in the same language as the most recent user message.",
);
expect(context.systemPrompt).toContain(
"Writing constraints: Keep responses under 120 words",
);
@ -104,6 +113,24 @@ describe("buildJobChatPromptContext", () => {
expect(context.systemPrompt).toContain("Writing style tone: professional.");
});
it("preserves language instructions inside global writing constraints", async () => {
const job = createJob({ id: "job-ctx-3" });
vi.mocked(getJobById).mockResolvedValue(job);
vi.mocked(getWritingStyle).mockResolvedValue({
tone: "professional",
formality: "medium",
constraints: "Always respond in French.",
doNotUse: "",
});
vi.mocked(getProfile).mockResolvedValue({});
const context = await buildJobChatPromptContext(job.id);
expect(context.systemPrompt).toContain(
"Writing constraints: Always respond in French.",
);
});
it("throws not found for unknown job", async () => {
vi.mocked(getJobById).mockResolvedValue(null);

View File

@ -103,6 +103,9 @@ function buildSystemPrompt(style: WritingStyle): string {
"Do not claim actions were executed. You are read-only and advisory.",
"If details are missing, say what is missing before making assumptions.",
"Avoid exposing private profile details that are unrelated to the user request.",
"Follow the user's requested output language exactly when they specify one.",
"If the global writing constraints specify an output language, follow that when the user has not requested a different language.",
"If no output language is specified elsewhere, reply in the same language as the most recent user message.",
`Writing style tone: ${style.tone}.`,
`Writing style formality: ${style.formality}.`,
style.constraints ? `Writing constraints: ${style.constraints}` : null,