ai-i18n-tools 1.8.8 → 1.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ai-i18n-tools +8 -0
- package/dist/api/llm-client.d.ts +43 -26
- package/dist/api/llm-client.d.ts.map +1 -1
- package/dist/api/llm-client.js +219 -17
- package/dist/api/llm-client.js.map +1 -1
- package/dist/build-info.generated.d.ts +1 -1
- package/dist/build-info.generated.js +1 -1
- package/dist/cli/doc-shell-ts-translate.d.ts.map +1 -1
- package/dist/cli/doc-shell-ts-translate.js +5 -3
- package/dist/cli/doc-shell-ts-translate.js.map +1 -1
- package/dist/cli/doc-translate.d.ts +1 -0
- package/dist/cli/doc-translate.d.ts.map +1 -1
- package/dist/cli/doc-translate.js +34 -77
- package/dist/cli/doc-translate.js.map +1 -1
- package/dist/cli/fumadocs-meta-translate.d.ts.map +1 -1
- package/dist/cli/fumadocs-meta-translate.js +5 -3
- package/dist/cli/fumadocs-meta-translate.js.map +1 -1
- package/dist/cli/fumadocs-ui-catalog.d.ts.map +1 -1
- package/dist/cli/fumadocs-ui-catalog.js +5 -4
- package/dist/cli/fumadocs-ui-catalog.js.map +1 -1
- package/dist/cli/index.js +9 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/translate-json-run.d.ts.map +1 -1
- package/dist/cli/translate-json-run.js +9 -5
- package/dist/cli/translate-json-run.js.map +1 -1
- package/dist/cli/translate-svg.d.ts.map +1 -1
- package/dist/cli/translate-svg.js +4 -1
- package/dist/cli/translate-svg.js.map +1 -1
- package/dist/cli/translate-ui-strings.d.ts +17 -0
- package/dist/cli/translate-ui-strings.d.ts.map +1 -1
- package/dist/cli/translate-ui-strings.js +106 -33
- package/dist/cli/translate-ui-strings.js.map +1 -1
- package/dist/cli/translation-failure-log.d.ts +3 -0
- package/dist/cli/translation-failure-log.d.ts.map +1 -0
- package/dist/cli/translation-failure-log.js +2 -0
- package/dist/cli/translation-failure-log.js.map +1 -0
- package/dist/cli/vitepress-theme-catalog.d.ts.map +1 -1
- package/dist/cli/vitepress-theme-catalog.js +5 -4
- package/dist/cli/vitepress-theme-catalog.js.map +1 -1
- package/dist/cli/write-heading-ids.d.ts.map +1 -1
- package/dist/cli/write-heading-ids.js +4 -0
- package/dist/cli/write-heading-ids.js.map +1 -1
- package/dist/core/config.d.ts +2 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +4 -2
- package/dist/core/config.js.map +1 -1
- package/dist/core/locale-utils.d.ts +48 -11
- package/dist/core/locale-utils.d.ts.map +1 -1
- package/dist/core/locale-utils.js +303 -23
- package/dist/core/locale-utils.js.map +1 -1
- package/dist/core/prompt-builder.d.ts +2 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +10 -5
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/prompts.d.ts +2 -2
- package/dist/core/prompts.d.ts.map +1 -1
- package/dist/core/prompts.js +3 -3
- package/dist/core/prompts.js.map +1 -1
- package/dist/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -1
- package/dist/extractors/svg-extractor.d.ts.map +1 -1
- package/dist/extractors/svg-extractor.js +73 -72
- package/dist/extractors/svg-extractor.js.map +1 -1
- package/dist/i18n/locales/de.json +4 -4
- package/dist/i18n/locales/es.json +4 -4
- package/dist/i18n/locales/fr.json +4 -4
- package/dist/i18n/locales/hi.json +4 -4
- package/dist/i18n/locales/ja.json +4 -4
- package/dist/i18n/locales/ko.json +4 -4
- package/dist/i18n/locales/pt-BR.json +4 -4
- package/dist/i18n/locales/zh-Hans.json +4 -4
- package/dist/i18n/locales/zh-Hant.json +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/markdown/write-heading-ids-core.d.ts +15 -5
- package/dist/markdown/write-heading-ids-core.d.ts.map +1 -1
- package/dist/markdown/write-heading-ids-core.js +100 -10
- package/dist/markdown/write-heading-ids-core.js.map +1 -1
- package/dist/processors/placeholder-integrity.d.ts +7 -8
- package/dist/processors/placeholder-integrity.d.ts.map +1 -1
- package/dist/processors/placeholder-integrity.js +56 -40
- package/dist/processors/placeholder-integrity.js.map +1 -1
- package/dist/utils/translation-failure-log.d.ts +42 -0
- package/dist/utils/translation-failure-log.d.ts.map +1 -0
- package/dist/utils/translation-failure-log.js +95 -0
- package/dist/utils/translation-failure-log.js.map +1 -0
- package/docs/ai-i18n-tools-context.md +1 -0
- package/package.json +11 -10
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PATH-friendly name (no .mjs suffix) beside the published package.json bin
|
|
4
|
+
* (`ai-i18n-tools.mjs`). With direnv `PATH_add bin` in `.envrc`, the bare
|
|
5
|
+
* `ai-i18n-tools` command works in this checkout. pnpm still does not link the
|
|
6
|
+
* root package's own bin into `node_modules/.bin`.
|
|
7
|
+
*/
|
|
8
|
+
import "./ai-i18n-tools.mjs";
|
package/dist/api/llm-client.d.ts
CHANGED
|
@@ -2,32 +2,27 @@ import type { CldrPluralForm, I18nConfig } from "../core/types.js";
|
|
|
2
2
|
import { type BatchTranslationResult, type ChatResponse, type LlmUsageStats, type Segment, type TranslationResult } from "../core/types.js";
|
|
3
3
|
import { type DocumentBatchResponseFormat, type DocumentPromptContentType, type ProofreadUISlotResult } from "../core/prompt-builder.js";
|
|
4
4
|
import type { Logger } from "../utils/logger.js";
|
|
5
|
+
/** Details attached when every model in a fallback chain fails. */
|
|
6
|
+
export interface LlmAllModelsFailedDetails {
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
userContent: string;
|
|
9
|
+
lastModel: string;
|
|
10
|
+
lastError: unknown;
|
|
11
|
+
/** HTTP response body text when the model returned content but parsing/validation failed. */
|
|
12
|
+
lastRawAssistantContent?: string;
|
|
13
|
+
/** Tokens spent across billed-but-discarded attempts before every model failed. */
|
|
14
|
+
wastedUsage?: LlmUsageStats;
|
|
15
|
+
/** USD cost spent across billed-but-discarded attempts (undefined when no cost was reported). */
|
|
16
|
+
wastedCost?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Thrown when every model in the chain fails for a translation request. */
|
|
19
|
+
export declare class LlmAllModelsFailedError extends Error {
|
|
20
|
+
readonly details: LlmAllModelsFailedDetails;
|
|
21
|
+
constructor(message: string, details: LlmAllModelsFailedDetails);
|
|
22
|
+
}
|
|
5
23
|
/** Thrown when every model in the chain fails for {@link LlmClient.translateDocumentBatch}. */
|
|
6
|
-
export declare class DocumentBatchAllModelsFailedError extends
|
|
7
|
-
|
|
8
|
-
systemPrompt: string;
|
|
9
|
-
userContent: string;
|
|
10
|
-
lastModel: string;
|
|
11
|
-
lastError: unknown;
|
|
12
|
-
/** HTTP response body text when the model returned content but parsing failed. */
|
|
13
|
-
lastRawAssistantContent?: string;
|
|
14
|
-
/** Tokens spent across billed-but-discarded attempts before every model failed. */
|
|
15
|
-
wastedUsage?: LlmUsageStats;
|
|
16
|
-
/** USD cost spent across billed-but-discarded attempts (undefined when no cost was reported). */
|
|
17
|
-
wastedCost?: number;
|
|
18
|
-
};
|
|
19
|
-
constructor(message: string, details: {
|
|
20
|
-
systemPrompt: string;
|
|
21
|
-
userContent: string;
|
|
22
|
-
lastModel: string;
|
|
23
|
-
lastError: unknown;
|
|
24
|
-
/** HTTP response body text when the model returned content but parsing failed. */
|
|
25
|
-
lastRawAssistantContent?: string;
|
|
26
|
-
/** Tokens spent across billed-but-discarded attempts before every model failed. */
|
|
27
|
-
wastedUsage?: LlmUsageStats;
|
|
28
|
-
/** USD cost spent across billed-but-discarded attempts (undefined when no cost was reported). */
|
|
29
|
-
wastedCost?: number;
|
|
30
|
-
});
|
|
24
|
+
export declare class DocumentBatchAllModelsFailedError extends LlmAllModelsFailedError {
|
|
25
|
+
constructor(message: string, details: LlmAllModelsFailedDetails);
|
|
31
26
|
}
|
|
32
27
|
export interface LlmClientOptions {
|
|
33
28
|
config: Pick<I18nConfig, "provider" | "providers" | "sourceLocale" | "localeDisplayNames">;
|
|
@@ -40,6 +35,17 @@ export interface LlmClientOptions {
|
|
|
40
35
|
translationModels?: string[];
|
|
41
36
|
/** Append request/response JSON when set. */
|
|
42
37
|
debugTrafficFilePath?: string | null;
|
|
38
|
+
/**
|
|
39
|
+
* When set (CLI `--debug-failed` → `cacheDir`), write a `FAILED-TRANSLATION` file for each
|
|
40
|
+
* discarded model attempt (script/parse/API), including fallbacks — not only the final
|
|
41
|
+
* all-models-failed throw.
|
|
42
|
+
*/
|
|
43
|
+
debugFailedDir?: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Path label used in `--debug-failed` logs for UI/plural/proofread batches. Document batches
|
|
46
|
+
* prefer `docLogContext.relativePath` when present.
|
|
47
|
+
*/
|
|
48
|
+
debugFailedRelativePath?: string;
|
|
43
49
|
logger?: Logger;
|
|
44
50
|
httpReferer?: string;
|
|
45
51
|
xTitle?: string;
|
|
@@ -67,6 +73,8 @@ export declare class LlmClient {
|
|
|
67
73
|
private readonly maxTokens;
|
|
68
74
|
private readonly temperature;
|
|
69
75
|
private readonly debugTrafficFilePath;
|
|
76
|
+
private readonly debugFailedDir;
|
|
77
|
+
private readonly debugFailedRelativePath;
|
|
70
78
|
private readonly logger?;
|
|
71
79
|
private readonly localeDisplayNames;
|
|
72
80
|
private readonly sourceLanguageLabel;
|
|
@@ -95,12 +103,21 @@ export declare class LlmClient {
|
|
|
95
103
|
* a stray foreign-language quote does not fail the output, and `zh-Hans`/`zh-Hant` are told
|
|
96
104
|
* apart via variant-distinct characters. Uses {@link effectiveScriptSubtag} so bare `hi`
|
|
97
105
|
* (Devanagari by default) is enforced like an explicit `*-Deva` tag. Locales with no
|
|
98
|
-
* effective script
|
|
106
|
+
* effective script are not enforced. Composite families (`Jpan`, `Kore`) are enforced as
|
|
107
|
+
* allowed-script sets. Fully Latin leftover that is not a preserved brand/code token is
|
|
108
|
+
* rejected for non-Latin targets.
|
|
99
109
|
*/
|
|
100
110
|
private assertExpectedScript;
|
|
111
|
+
private assertBatchExpectedScript;
|
|
101
112
|
private appendDebugLog;
|
|
102
113
|
/** Match doc-translate log lines: two-space indent, locale, filename. */
|
|
103
114
|
private warnModelSwitch;
|
|
115
|
+
/**
|
|
116
|
+
* Persist prompt + raw output + validation error for a discarded model attempt when
|
|
117
|
+
* `--debug-failed` supplied `debugFailedDir`.
|
|
118
|
+
*/
|
|
119
|
+
private logFailedModelAttempt;
|
|
120
|
+
private static promptPartsFromMessages;
|
|
104
121
|
private toOpenRouterMessages;
|
|
105
122
|
private static emptyDiscarded;
|
|
106
123
|
/** Add a billed-but-discarded attempt's tokens/cost onto the running discarded total. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/api/llm-client.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/api/llm-client.ts"],"names":[],"mappings":"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"}
|
package/dist/api/llm-client.js
CHANGED
|
@@ -4,10 +4,11 @@ import { generateText } from "ai";
|
|
|
4
4
|
import { createOpenAICompatible, } from "@ai-sdk/openai-compatible";
|
|
5
5
|
import { BatchTranslationError, } from "../core/types.js";
|
|
6
6
|
import { englishLanguageNameForLocale, normalizeLocale, resolveTranslationModels, } from "../core/config.js";
|
|
7
|
-
import { effectiveScriptSubtag, scriptValidationIssue } from "../core/locale-utils.js";
|
|
7
|
+
import { batchTranslationScriptIssue, effectiveScriptSubtag, scriptValidationIssue, } from "../core/locale-utils.js";
|
|
8
8
|
import { OPENROUTER_PROVIDER_KEY, resolveActiveProvider, resolveApiKey, resolveProviderSettings, } from "../core/llm-providers.js";
|
|
9
9
|
import { buildDocumentBatchPrompt, buildDocumentSinglePrompt, buildProofreadUIPromptMessages, buildUIPromptMessages, parseBatchJsonArrayResponse, parseBatchJsonObjectResponse, parseBatchTranslationResponse, parseProofreadUIBatchResponse, parsePluralFormsJsonResponse, parseUIJsonArrayResponse, ScriptValidationError, } from "../core/prompt-builder.js";
|
|
10
10
|
import { assertPluralFormsPlaceholders } from "../core/plural-placeholders.js";
|
|
11
|
+
import { warnTranslationFailureLogPath, writeTranslationFailureLog, } from "../utils/translation-failure-log.js";
|
|
11
12
|
/** OpenRouter: prefer throughput; allow backup providers (top-level `provider` routing field). */
|
|
12
13
|
const OPENROUTER_PROVIDER = {
|
|
13
14
|
sort: "throughput",
|
|
@@ -41,11 +42,18 @@ const openRouterMetadataExtractor = {
|
|
|
41
42
|
buildMetadata: () => undefined,
|
|
42
43
|
}),
|
|
43
44
|
};
|
|
44
|
-
/** Thrown when every model in the chain fails for
|
|
45
|
-
export class
|
|
45
|
+
/** Thrown when every model in the chain fails for a translation request. */
|
|
46
|
+
export class LlmAllModelsFailedError extends Error {
|
|
46
47
|
constructor(message, details) {
|
|
47
48
|
super(message);
|
|
48
49
|
this.details = details;
|
|
50
|
+
this.name = "LlmAllModelsFailedError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Thrown when every model in the chain fails for {@link LlmClient.translateDocumentBatch}. */
|
|
54
|
+
export class DocumentBatchAllModelsFailedError extends LlmAllModelsFailedError {
|
|
55
|
+
constructor(message, details) {
|
|
56
|
+
super(message, details);
|
|
49
57
|
this.name = "DocumentBatchAllModelsFailedError";
|
|
50
58
|
}
|
|
51
59
|
}
|
|
@@ -85,6 +93,8 @@ export class LlmClient {
|
|
|
85
93
|
this.temperature = settings.temperature;
|
|
86
94
|
this.requestTimeoutMs = settings.requestTimeoutMs;
|
|
87
95
|
this.debugTrafficFilePath = opts.debugTrafficFilePath ?? null;
|
|
96
|
+
this.debugFailedDir = opts.debugFailedDir ?? null;
|
|
97
|
+
this.debugFailedRelativePath = opts.debugFailedRelativePath?.trim() || "llm-batch";
|
|
88
98
|
this.logger = opts.logger;
|
|
89
99
|
this.localeDisplayNames = {};
|
|
90
100
|
for (const [k, v] of Object.entries(opts.config.localeDisplayNames ?? {})) {
|
|
@@ -153,20 +163,30 @@ export class LlmClient {
|
|
|
153
163
|
* a stray foreign-language quote does not fail the output, and `zh-Hans`/`zh-Hant` are told
|
|
154
164
|
* apart via variant-distinct characters. Uses {@link effectiveScriptSubtag} so bare `hi`
|
|
155
165
|
* (Devanagari by default) is enforced like an explicit `*-Deva` tag. Locales with no
|
|
156
|
-
* effective script
|
|
166
|
+
* effective script are not enforced. Composite families (`Jpan`, `Kore`) are enforced as
|
|
167
|
+
* allowed-script sets. Fully Latin leftover that is not a preserved brand/code token is
|
|
168
|
+
* rejected for non-Latin targets.
|
|
157
169
|
*/
|
|
158
|
-
assertExpectedScript(text, targetLocale) {
|
|
170
|
+
assertExpectedScript(text, targetLocale, sourceText) {
|
|
159
171
|
const script = effectiveScriptSubtag(targetLocale);
|
|
160
172
|
if (!script) {
|
|
161
173
|
return;
|
|
162
174
|
}
|
|
163
|
-
const issue = scriptValidationIssue(text, script);
|
|
175
|
+
const issue = scriptValidationIssue(text, script, sourceText !== undefined ? { sourceText } : undefined);
|
|
164
176
|
if (!issue) {
|
|
165
177
|
return;
|
|
166
178
|
}
|
|
167
179
|
const suffix = issue.sample.length > 0 ? ` (${issue.sample.join(" ")})` : "";
|
|
168
180
|
throw new ScriptValidationError(`Output for ${targetLocale} ${issue.message}${suffix}`, text, issue.sample);
|
|
169
181
|
}
|
|
182
|
+
assertBatchExpectedScript(outputs, sources, targetLocale) {
|
|
183
|
+
const issue = batchTranslationScriptIssue(outputs, sources, targetLocale);
|
|
184
|
+
if (!issue) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const suffix = issue.sample.length > 0 ? ` (${issue.sample.join(" ")})` : "";
|
|
188
|
+
throw new ScriptValidationError(`Output for ${targetLocale} ${issue.message}${suffix}`, outputs.join("\n"), issue.sample);
|
|
189
|
+
}
|
|
170
190
|
appendDebugLog(direction, payload) {
|
|
171
191
|
if (!this.debugTrafficFilePath) {
|
|
172
192
|
return;
|
|
@@ -187,6 +207,43 @@ export class LlmClient {
|
|
|
187
207
|
const detail = error instanceof Error ? error.message : String(error);
|
|
188
208
|
console.warn(chalk.yellow(` ⚠️ ${loc}: ${failedModel} failed (${detail}). Trying ${nextModel}…`));
|
|
189
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Persist prompt + raw output + validation error for a discarded model attempt when
|
|
212
|
+
* `--debug-failed` supplied `debugFailedDir`.
|
|
213
|
+
*/
|
|
214
|
+
logFailedModelAttempt(args) {
|
|
215
|
+
if (!this.debugFailedDir) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const nextModel = this.modelsToTry[args.modelIndex + 1];
|
|
219
|
+
const errMsg = args.error instanceof Error ? args.error.message : String(args.error);
|
|
220
|
+
warnTranslationFailureLogPath(writeTranslationFailureLog({
|
|
221
|
+
cacheDirAbs: this.debugFailedDir,
|
|
222
|
+
relativePath: args.relativePath,
|
|
223
|
+
locale: args.locale,
|
|
224
|
+
segmentsLabel: args.segmentsLabel ?? "batch",
|
|
225
|
+
outcome: nextModel ? "retrying_next_model" : "fatal",
|
|
226
|
+
failedModel: args.model,
|
|
227
|
+
nextModel,
|
|
228
|
+
qualityErrors: [errMsg],
|
|
229
|
+
perSegmentLines: [],
|
|
230
|
+
systemPrompt: args.systemPrompt,
|
|
231
|
+
userContent: args.userContent,
|
|
232
|
+
rawAssistantContent: args.rawAssistantContent ?? "",
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
static promptPartsFromMessages(messages) {
|
|
236
|
+
return {
|
|
237
|
+
systemPrompt: messages
|
|
238
|
+
.filter((m) => m.role === "system")
|
|
239
|
+
.map((m) => m.content)
|
|
240
|
+
.join("\n\n"),
|
|
241
|
+
userContent: messages
|
|
242
|
+
.filter((m) => m.role === "user")
|
|
243
|
+
.map((m) => m.content)
|
|
244
|
+
.join("\n\n"),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
190
247
|
toOpenRouterMessages(messages) {
|
|
191
248
|
return messages.map((m) => ({ role: m.role, content: m.content }));
|
|
192
249
|
}
|
|
@@ -288,9 +345,12 @@ export class LlmClient {
|
|
|
288
345
|
const start = Math.max(0, Math.floor(options?.startModelIndex ?? 0));
|
|
289
346
|
let lastError;
|
|
290
347
|
const discarded = LlmClient.emptyDiscarded();
|
|
348
|
+
const promptParts = LlmClient.promptPartsFromMessages(messages);
|
|
349
|
+
const failedPath = options?.docLogContext?.relativePath ?? this.debugFailedRelativePath;
|
|
350
|
+
const failedLocale = options?.docLogContext?.locale ?? "unknown";
|
|
291
351
|
for (let mi = start; mi < this.modelsToTry.length; mi++) {
|
|
292
352
|
const model = this.modelsToTry[mi];
|
|
293
|
-
const
|
|
353
|
+
const recordFailure = (e, rawAssistantContent) => {
|
|
294
354
|
const nextModel = this.modelsToTry[mi + 1];
|
|
295
355
|
if (nextModel && options?.docLogContext) {
|
|
296
356
|
this.warnModelSwitch(options.docLogContext.locale, options.docLogContext.relativePath, model, nextModel, e);
|
|
@@ -298,6 +358,16 @@ export class LlmClient {
|
|
|
298
358
|
else if (!options?.docLogContext) {
|
|
299
359
|
this.logger?.warn(`Model ${model} failed: ${e}`);
|
|
300
360
|
}
|
|
361
|
+
this.logFailedModelAttempt({
|
|
362
|
+
locale: failedLocale,
|
|
363
|
+
relativePath: failedPath,
|
|
364
|
+
model,
|
|
365
|
+
modelIndex: mi,
|
|
366
|
+
error: e,
|
|
367
|
+
systemPrompt: promptParts.systemPrompt,
|
|
368
|
+
userContent: promptParts.userContent,
|
|
369
|
+
rawAssistantContent,
|
|
370
|
+
});
|
|
301
371
|
};
|
|
302
372
|
let completion;
|
|
303
373
|
try {
|
|
@@ -308,7 +378,7 @@ export class LlmClient {
|
|
|
308
378
|
if (e instanceof BilledCompletionError) {
|
|
309
379
|
LlmClient.addDiscarded(discarded, e.usage, e.cost);
|
|
310
380
|
}
|
|
311
|
-
|
|
381
|
+
recordFailure(e);
|
|
312
382
|
continue;
|
|
313
383
|
}
|
|
314
384
|
try {
|
|
@@ -317,7 +387,7 @@ export class LlmClient {
|
|
|
317
387
|
catch (e) {
|
|
318
388
|
lastError = e;
|
|
319
389
|
LlmClient.addDiscarded(discarded, completion.usage, completion.cost);
|
|
320
|
-
|
|
390
|
+
recordFailure(e, completion.content);
|
|
321
391
|
continue;
|
|
322
392
|
}
|
|
323
393
|
const folded = LlmClient.foldDiscarded(completion.usage, completion.cost, discarded);
|
|
@@ -345,7 +415,7 @@ export class LlmClient {
|
|
|
345
415
|
], {
|
|
346
416
|
startModelIndex: options?.startModelIndex,
|
|
347
417
|
docLogContext: options?.docLogContext,
|
|
348
|
-
validateResponse: (c) => this.assertExpectedScript(this.stripTranslateTags(c), targetLocale),
|
|
418
|
+
validateResponse: (c) => this.assertExpectedScript(this.stripTranslateTags(c), targetLocale, content),
|
|
349
419
|
});
|
|
350
420
|
return {
|
|
351
421
|
content: this.stripTranslateTags(res.content),
|
|
@@ -410,6 +480,15 @@ export class LlmClient {
|
|
|
410
480
|
this.logger?.warn(`Batch request failed with ${model}: ${e}`);
|
|
411
481
|
}
|
|
412
482
|
}
|
|
483
|
+
this.logFailedModelAttempt({
|
|
484
|
+
locale,
|
|
485
|
+
relativePath: options?.docLogContext?.relativePath ?? this.debugFailedRelativePath,
|
|
486
|
+
model,
|
|
487
|
+
modelIndex: mi,
|
|
488
|
+
error: e,
|
|
489
|
+
systemPrompt,
|
|
490
|
+
userContent,
|
|
491
|
+
});
|
|
413
492
|
continue;
|
|
414
493
|
}
|
|
415
494
|
try {
|
|
@@ -423,9 +502,20 @@ export class LlmClient {
|
|
|
423
502
|
else {
|
|
424
503
|
translations = parseBatchTranslationResponse(completion.content, segments.length, completion.content);
|
|
425
504
|
}
|
|
426
|
-
for (const value of translations.
|
|
427
|
-
this.assertExpectedScript(value, locale);
|
|
505
|
+
for (const [index, value] of translations.entries()) {
|
|
506
|
+
this.assertExpectedScript(value, locale, segments[index]?.content);
|
|
507
|
+
}
|
|
508
|
+
const batchOutputs = [];
|
|
509
|
+
const batchSources = [];
|
|
510
|
+
for (let i = 0; i < segments.length; i++) {
|
|
511
|
+
const value = translations.get(i);
|
|
512
|
+
if (value === undefined) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
batchOutputs.push(value);
|
|
516
|
+
batchSources.push(segments[i]?.content ?? "");
|
|
428
517
|
}
|
|
518
|
+
this.assertBatchExpectedScript(batchOutputs, batchSources, locale);
|
|
429
519
|
const folded = LlmClient.foldDiscarded(completion.usage, completion.cost, discarded);
|
|
430
520
|
return {
|
|
431
521
|
translations,
|
|
@@ -458,6 +548,16 @@ export class LlmClient {
|
|
|
458
548
|
this.logger?.warn(`Batch parse failed with ${model}: ${e}`);
|
|
459
549
|
}
|
|
460
550
|
}
|
|
551
|
+
this.logFailedModelAttempt({
|
|
552
|
+
locale,
|
|
553
|
+
relativePath: options?.docLogContext?.relativePath ?? this.debugFailedRelativePath,
|
|
554
|
+
model,
|
|
555
|
+
modelIndex: mi,
|
|
556
|
+
error: e,
|
|
557
|
+
systemPrompt,
|
|
558
|
+
userContent,
|
|
559
|
+
rawAssistantContent: completion.content,
|
|
560
|
+
});
|
|
461
561
|
}
|
|
462
562
|
}
|
|
463
563
|
const msg = `All translation models failed for batch (${this.modelsToTry.slice(start).join(", ")}). Last error: ${lastError instanceof Error ? lastError.message : String(lastError)}`;
|
|
@@ -503,6 +603,7 @@ export class LlmClient {
|
|
|
503
603
|
const start = Math.max(0, Math.floor(options?.startModelIndex ?? 0));
|
|
504
604
|
let lastError;
|
|
505
605
|
const discarded = LlmClient.emptyDiscarded();
|
|
606
|
+
let lastFailureDetails;
|
|
506
607
|
for (let mi = start; mi < this.modelsToTry.length; mi++) {
|
|
507
608
|
const model = this.modelsToTry[mi];
|
|
508
609
|
let result;
|
|
@@ -514,14 +615,31 @@ export class LlmClient {
|
|
|
514
615
|
if (e instanceof BilledCompletionError) {
|
|
515
616
|
LlmClient.addDiscarded(discarded, e.usage, e.cost);
|
|
516
617
|
}
|
|
618
|
+
lastFailureDetails = {
|
|
619
|
+
systemPrompt,
|
|
620
|
+
userContent,
|
|
621
|
+
lastModel: model,
|
|
622
|
+
lastError: e,
|
|
623
|
+
};
|
|
517
624
|
this.logger?.warn(`UI batch failed with ${model}: ${e}`);
|
|
625
|
+
this.logFailedModelAttempt({
|
|
626
|
+
locale: targetLocale,
|
|
627
|
+
relativePath: this.debugFailedRelativePath,
|
|
628
|
+
model,
|
|
629
|
+
modelIndex: mi,
|
|
630
|
+
error: e,
|
|
631
|
+
systemPrompt,
|
|
632
|
+
userContent,
|
|
633
|
+
segmentsLabel: "ui-batch",
|
|
634
|
+
});
|
|
518
635
|
continue;
|
|
519
636
|
}
|
|
520
637
|
try {
|
|
521
638
|
const translations = parseUIJsonArrayResponse(result.content, texts.length);
|
|
522
|
-
for (
|
|
523
|
-
this.assertExpectedScript(
|
|
639
|
+
for (let i = 0; i < translations.length; i++) {
|
|
640
|
+
this.assertExpectedScript(translations[i], targetLocale, texts[i]);
|
|
524
641
|
}
|
|
642
|
+
this.assertBatchExpectedScript(translations, texts, targetLocale);
|
|
525
643
|
const folded = LlmClient.foldDiscarded(result.usage, result.cost, discarded);
|
|
526
644
|
return {
|
|
527
645
|
translations,
|
|
@@ -533,10 +651,33 @@ export class LlmClient {
|
|
|
533
651
|
catch (e) {
|
|
534
652
|
lastError = e;
|
|
535
653
|
LlmClient.addDiscarded(discarded, result.usage, result.cost);
|
|
654
|
+
lastFailureDetails = {
|
|
655
|
+
systemPrompt,
|
|
656
|
+
userContent,
|
|
657
|
+
lastModel: model,
|
|
658
|
+
lastError: e,
|
|
659
|
+
lastRawAssistantContent: result.content,
|
|
660
|
+
};
|
|
536
661
|
this.logger?.warn(`UI batch failed with ${model}: ${e}`);
|
|
662
|
+
this.logFailedModelAttempt({
|
|
663
|
+
locale: targetLocale,
|
|
664
|
+
relativePath: this.debugFailedRelativePath,
|
|
665
|
+
model,
|
|
666
|
+
modelIndex: mi,
|
|
667
|
+
error: e,
|
|
668
|
+
systemPrompt,
|
|
669
|
+
userContent,
|
|
670
|
+
rawAssistantContent: result.content,
|
|
671
|
+
segmentsLabel: "ui-batch",
|
|
672
|
+
});
|
|
537
673
|
}
|
|
538
674
|
}
|
|
539
|
-
throw new
|
|
675
|
+
throw new LlmAllModelsFailedError(`All translation models failed for UI batch (${this.modelsToTry.slice(start).join(", ")}). Last error: ${lastError instanceof Error ? lastError.message : String(lastError)}`, lastFailureDetails ?? {
|
|
676
|
+
systemPrompt,
|
|
677
|
+
userContent,
|
|
678
|
+
lastModel: this.modelsToTry[Math.max(0, this.modelsToTry.length - 1)],
|
|
679
|
+
lastError,
|
|
680
|
+
});
|
|
540
681
|
}
|
|
541
682
|
/**
|
|
542
683
|
* `proofread-ui`: review a batch of source-locale UI strings; model returns JSON array of `{ issues: [...] }`.
|
|
@@ -573,6 +714,16 @@ export class LlmClient {
|
|
|
573
714
|
LlmClient.addDiscarded(discarded, e.usage, e.cost);
|
|
574
715
|
}
|
|
575
716
|
this.logger?.warn(`proofread-ui batch failed with ${model}: ${e}`);
|
|
717
|
+
this.logFailedModelAttempt({
|
|
718
|
+
locale: languageLabel,
|
|
719
|
+
relativePath: this.debugFailedRelativePath,
|
|
720
|
+
model,
|
|
721
|
+
modelIndex: mi,
|
|
722
|
+
error: e,
|
|
723
|
+
systemPrompt,
|
|
724
|
+
userContent,
|
|
725
|
+
segmentsLabel: "proofread-ui",
|
|
726
|
+
});
|
|
576
727
|
continue;
|
|
577
728
|
}
|
|
578
729
|
try {
|
|
@@ -590,6 +741,17 @@ export class LlmClient {
|
|
|
590
741
|
lastError = e;
|
|
591
742
|
LlmClient.addDiscarded(discarded, result.usage, result.cost);
|
|
592
743
|
this.logger?.warn(`proofread-ui batch failed with ${model}: ${e}`);
|
|
744
|
+
this.logFailedModelAttempt({
|
|
745
|
+
locale: languageLabel,
|
|
746
|
+
relativePath: this.debugFailedRelativePath,
|
|
747
|
+
model,
|
|
748
|
+
modelIndex: mi,
|
|
749
|
+
error: e,
|
|
750
|
+
systemPrompt,
|
|
751
|
+
userContent,
|
|
752
|
+
rawAssistantContent: result.content,
|
|
753
|
+
segmentsLabel: "proofread-ui",
|
|
754
|
+
});
|
|
593
755
|
}
|
|
594
756
|
}
|
|
595
757
|
throw new Error(`All translation models failed for proofread-ui batch (${this.modelsToTry.slice(start).join(", ")}). Last error: ${lastError}`);
|
|
@@ -612,6 +774,7 @@ export class LlmClient {
|
|
|
612
774
|
const start = Math.max(0, Math.floor(options?.startModelIndex ?? 0));
|
|
613
775
|
let lastError;
|
|
614
776
|
const discarded = LlmClient.emptyDiscarded();
|
|
777
|
+
let lastFailureDetails;
|
|
615
778
|
for (let mi = start; mi < this.modelsToTry.length; mi++) {
|
|
616
779
|
const model = this.modelsToTry[mi];
|
|
617
780
|
let result;
|
|
@@ -623,7 +786,23 @@ export class LlmClient {
|
|
|
623
786
|
if (e instanceof BilledCompletionError) {
|
|
624
787
|
LlmClient.addDiscarded(discarded, e.usage, e.cost);
|
|
625
788
|
}
|
|
789
|
+
lastFailureDetails = {
|
|
790
|
+
systemPrompt: messages.systemPrompt,
|
|
791
|
+
userContent: messages.userContent,
|
|
792
|
+
lastModel: model,
|
|
793
|
+
lastError: e,
|
|
794
|
+
};
|
|
626
795
|
this.logger?.warn(`Plural cardinal batch failed with ${model}: ${e}`);
|
|
796
|
+
this.logFailedModelAttempt({
|
|
797
|
+
locale: options?.targetLocale ?? "unknown",
|
|
798
|
+
relativePath: this.debugFailedRelativePath,
|
|
799
|
+
model,
|
|
800
|
+
modelIndex: mi,
|
|
801
|
+
error: e,
|
|
802
|
+
systemPrompt: messages.systemPrompt,
|
|
803
|
+
userContent: messages.userContent,
|
|
804
|
+
segmentsLabel: "plural-batch",
|
|
805
|
+
});
|
|
627
806
|
continue;
|
|
628
807
|
}
|
|
629
808
|
try {
|
|
@@ -636,7 +815,7 @@ export class LlmClient {
|
|
|
636
815
|
}
|
|
637
816
|
if (options?.targetLocale) {
|
|
638
817
|
for (const value of Object.values(forms)) {
|
|
639
|
-
this.assertExpectedScript(value, options.targetLocale);
|
|
818
|
+
this.assertExpectedScript(value, options.targetLocale, options.originalLiteral);
|
|
640
819
|
}
|
|
641
820
|
}
|
|
642
821
|
const folded = LlmClient.foldDiscarded(result.usage, result.cost, discarded);
|
|
@@ -651,10 +830,33 @@ export class LlmClient {
|
|
|
651
830
|
catch (e) {
|
|
652
831
|
lastError = e;
|
|
653
832
|
LlmClient.addDiscarded(discarded, result.usage, result.cost);
|
|
833
|
+
lastFailureDetails = {
|
|
834
|
+
systemPrompt: messages.systemPrompt,
|
|
835
|
+
userContent: messages.userContent,
|
|
836
|
+
lastModel: model,
|
|
837
|
+
lastError: e,
|
|
838
|
+
lastRawAssistantContent: result.content,
|
|
839
|
+
};
|
|
654
840
|
this.logger?.warn(`Plural cardinal batch failed with ${model}: ${e}`);
|
|
841
|
+
this.logFailedModelAttempt({
|
|
842
|
+
locale: options?.targetLocale ?? "unknown",
|
|
843
|
+
relativePath: this.debugFailedRelativePath,
|
|
844
|
+
model,
|
|
845
|
+
modelIndex: mi,
|
|
846
|
+
error: e,
|
|
847
|
+
systemPrompt: messages.systemPrompt,
|
|
848
|
+
userContent: messages.userContent,
|
|
849
|
+
rawAssistantContent: result.content,
|
|
850
|
+
segmentsLabel: "plural-batch",
|
|
851
|
+
});
|
|
655
852
|
}
|
|
656
853
|
}
|
|
657
|
-
throw new
|
|
854
|
+
throw new LlmAllModelsFailedError(`All translation models failed for plural cardinal batch (${this.modelsToTry.slice(start).join(", ")}). Last error: ${lastError instanceof Error ? lastError.message : String(lastError)}`, lastFailureDetails ?? {
|
|
855
|
+
systemPrompt: messages.systemPrompt,
|
|
856
|
+
userContent: messages.userContent,
|
|
857
|
+
lastModel: this.modelsToTry[Math.max(0, this.modelsToTry.length - 1)],
|
|
858
|
+
lastError,
|
|
859
|
+
});
|
|
658
860
|
}
|
|
659
861
|
}
|
|
660
862
|
/** @deprecated Use {@link LlmClient}. Retained for backward-compatible imports. */
|