@purposeinplay/payload-ai-translate 0.1.0
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/LICENSE +21 -0
- package/README.md +714 -0
- package/dist/alerts-collection.d.ts +21 -0
- package/dist/alerts-collection.js +159 -0
- package/dist/api.d.ts +4 -0
- package/dist/api.js +918 -0
- package/dist/bulk-translate-batches-collection.d.ts +29 -0
- package/dist/bulk-translate-batches-collection.js +404 -0
- package/dist/bulk-translate-units-collection.d.ts +35 -0
- package/dist/bulk-translate-units-collection.js +310 -0
- package/dist/client/estimated-cost-cell.d.ts +6 -0
- package/dist/client/estimated-cost-cell.js +12 -0
- package/dist/client/excluded-fields-field.d.ts +45 -0
- package/dist/client/excluded-fields-field.js +553 -0
- package/dist/client/field-translate-button.d.ts +6 -0
- package/dist/client/field-translate-button.js +199 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +6 -0
- package/dist/client/lib/use-global-kill-switches.d.ts +20 -0
- package/dist/client/lib/use-global-kill-switches.js +58 -0
- package/dist/client/translate-button.d.ts +2 -0
- package/dist/client/translate-button.js +228 -0
- package/dist/client/translate-modal.d.ts +16 -0
- package/dist/client/translate-modal.js +549 -0
- package/dist/client/translation-progress.d.ts +10 -0
- package/dist/client/translation-progress.js +297 -0
- package/dist/components/TranslationNavGroup.d.ts +45 -0
- package/dist/components/TranslationNavGroup.js +104 -0
- package/dist/defaults.d.ts +11 -0
- package/dist/defaults.js +16 -0
- package/dist/endpoints/client-config.d.ts +44 -0
- package/dist/endpoints/client-config.js +145 -0
- package/dist/endpoints/estimate.d.ts +5 -0
- package/dist/endpoints/estimate.js +237 -0
- package/dist/endpoints/progress.d.ts +2 -0
- package/dist/endpoints/progress.js +314 -0
- package/dist/endpoints/translate.d.ts +11 -0
- package/dist/endpoints/translate.js +376 -0
- package/dist/endpoints/translation-hub/_helpers.d.ts +140 -0
- package/dist/endpoints/translation-hub/_helpers.js +297 -0
- package/dist/endpoints/translation-hub/active.d.ts +21 -0
- package/dist/endpoints/translation-hub/active.js +220 -0
- package/dist/endpoints/translation-hub/cancel.d.ts +22 -0
- package/dist/endpoints/translation-hub/cancel.js +233 -0
- package/dist/endpoints/translation-hub/enqueue.d.ts +70 -0
- package/dist/endpoints/translation-hub/enqueue.js +529 -0
- package/dist/endpoints/translation-hub/failures.d.ts +12 -0
- package/dist/endpoints/translation-hub/failures.js +67 -0
- package/dist/endpoints/translation-hub/force-reset.d.ts +20 -0
- package/dist/endpoints/translation-hub/force-reset.js +144 -0
- package/dist/endpoints/translation-hub/index.d.ts +21 -0
- package/dist/endpoints/translation-hub/index.js +20 -0
- package/dist/endpoints/translation-hub/list.d.ts +40 -0
- package/dist/endpoints/translation-hub/list.js +182 -0
- package/dist/endpoints/translation-hub/preflight.d.ts +19 -0
- package/dist/endpoints/translation-hub/preflight.js +141 -0
- package/dist/endpoints/translation-hub/retry-failed.d.ts +38 -0
- package/dist/endpoints/translation-hub/retry-failed.js +235 -0
- package/dist/endpoints/translation-hub/revert.d.ts +88 -0
- package/dist/endpoints/translation-hub/revert.js +405 -0
- package/dist/endpoints/translation-hub/status.d.ts +45 -0
- package/dist/endpoints/translation-hub/status.js +391 -0
- package/dist/endpoints/translation-hub/usage-summary.d.ts +114 -0
- package/dist/endpoints/translation-hub/usage-summary.js +481 -0
- package/dist/exports/client.d.ts +6 -0
- package/dist/exports/client.js +6 -0
- package/dist/exports/components.d.ts +6 -0
- package/dist/exports/components.js +5 -0
- package/dist/exports/index.d.ts +8 -0
- package/dist/exports/index.js +7 -0
- package/dist/exports/providers.d.ts +9 -0
- package/dist/exports/providers.js +5 -0
- package/dist/exports/views-client.d.ts +23 -0
- package/dist/exports/views-client.js +22 -0
- package/dist/exports/views.d.ts +30 -0
- package/dist/exports/views.js +29 -0
- package/dist/hooks/after-change-global.d.ts +4 -0
- package/dist/hooks/after-change-global.js +109 -0
- package/dist/hooks/after-change.d.ts +16 -0
- package/dist/hooks/after-change.js +205 -0
- package/dist/hooks/after-delete.d.ts +30 -0
- package/dist/hooks/after-delete.js +95 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/jobs-collection.d.ts +17 -0
- package/dist/jobs-collection.js +139 -0
- package/dist/lexical/classifier.d.ts +3 -0
- package/dist/lexical/classifier.js +108 -0
- package/dist/lexical/deserializer.d.ts +4 -0
- package/dist/lexical/deserializer.js +263 -0
- package/dist/lexical/placeholder-integrity.d.ts +6 -0
- package/dist/lexical/placeholder-integrity.js +21 -0
- package/dist/lexical/placeholders.d.ts +21 -0
- package/dist/lexical/placeholders.js +117 -0
- package/dist/lexical/serializer.d.ts +21 -0
- package/dist/lexical/serializer.js +233 -0
- package/dist/lexical/types.d.ts +32 -0
- package/dist/lexical/types.js +1 -0
- package/dist/lib/auth-diagnostics.d.ts +14 -0
- package/dist/lib/auth-diagnostics.js +19 -0
- package/dist/lib/batch-counts.d.ts +58 -0
- package/dist/lib/batch-counts.js +105 -0
- package/dist/lib/bulk-translate-migrations.d.ts +92 -0
- package/dist/lib/bulk-translate-migrations.js +153 -0
- package/dist/lib/coalescing-queue.d.ts +38 -0
- package/dist/lib/coalescing-queue.js +69 -0
- package/dist/lib/content-extractor.d.ts +16 -0
- package/dist/lib/content-extractor.js +410 -0
- package/dist/lib/content-hash.d.ts +1 -0
- package/dist/lib/content-hash.js +19 -0
- package/dist/lib/content-patcher.d.ts +15 -0
- package/dist/lib/content-patcher.js +293 -0
- package/dist/lib/cost-guards.d.ts +2 -0
- package/dist/lib/cost-guards.js +18 -0
- package/dist/lib/daily-spend-cap.d.ts +58 -0
- package/dist/lib/daily-spend-cap.js +233 -0
- package/dist/lib/effective-locales.d.ts +181 -0
- package/dist/lib/effective-locales.js +302 -0
- package/dist/lib/error-messages.d.ts +245 -0
- package/dist/lib/error-messages.js +626 -0
- package/dist/lib/events.d.ts +39 -0
- package/dist/lib/events.js +146 -0
- package/dist/lib/exclude-fields.d.ts +3 -0
- package/dist/lib/exclude-fields.js +64 -0
- package/dist/lib/field-breadcrumb.d.ts +31 -0
- package/dist/lib/field-breadcrumb.js +227 -0
- package/dist/lib/field-diff.d.ts +1 -0
- package/dist/lib/field-diff.js +25 -0
- package/dist/lib/field-empty.d.ts +2 -0
- package/dist/lib/field-empty.js +68 -0
- package/dist/lib/field-resolver.d.ts +3 -0
- package/dist/lib/field-resolver.js +164 -0
- package/dist/lib/group-soft-skips.d.ts +39 -0
- package/dist/lib/group-soft-skips.js +45 -0
- package/dist/lib/locale-merge.d.ts +44 -0
- package/dist/lib/locale-merge.js +357 -0
- package/dist/lib/locale-row-check.d.ts +30 -0
- package/dist/lib/locale-row-check.js +64 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +97 -0
- package/dist/lib/manual-edit-guard.d.ts +128 -0
- package/dist/lib/manual-edit-guard.js +393 -0
- package/dist/lib/output-validation.d.ts +48 -0
- package/dist/lib/output-validation.js +148 -0
- package/dist/lib/payload-read.d.ts +16 -0
- package/dist/lib/payload-read.js +51 -0
- package/dist/lib/per-doc-claim.d.ts +90 -0
- package/dist/lib/per-doc-claim.js +140 -0
- package/dist/lib/per-doc-lock.d.ts +94 -0
- package/dist/lib/per-doc-lock.js +119 -0
- package/dist/lib/persist-usage.d.ts +91 -0
- package/dist/lib/persist-usage.js +116 -0
- package/dist/lib/progress-store.d.ts +103 -0
- package/dist/lib/progress-store.js +314 -0
- package/dist/lib/rate-limiter.d.ts +3 -0
- package/dist/lib/rate-limiter.js +53 -0
- package/dist/lib/snapshot-select.d.ts +43 -0
- package/dist/lib/snapshot-select.js +108 -0
- package/dist/lib/translate-prompt.d.ts +31 -0
- package/dist/lib/translate-prompt.js +66 -0
- package/dist/lib/translation-token-bucket.d.ts +57 -0
- package/dist/lib/translation-token-bucket.js +365 -0
- package/dist/lib/truncate-source-value.d.ts +1 -0
- package/dist/lib/truncate-source-value.js +27 -0
- package/dist/manual-edit-collection.d.ts +22 -0
- package/dist/manual-edit-collection.js +124 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +934 -0
- package/dist/providers/ai-sdk-adapter.d.ts +35 -0
- package/dist/providers/ai-sdk-adapter.js +100 -0
- package/dist/providers/anthropic.d.ts +31 -0
- package/dist/providers/anthropic.js +66 -0
- package/dist/providers/custom.d.ts +36 -0
- package/dist/providers/custom.js +24 -0
- package/dist/providers/gemini.d.ts +20 -0
- package/dist/providers/gemini.js +48 -0
- package/dist/providers/mock.d.ts +2 -0
- package/dist/providers/mock.js +29 -0
- package/dist/providers/openai.d.ts +28 -0
- package/dist/providers/openai.js +69 -0
- package/dist/settings-global.d.ts +74 -0
- package/dist/settings-global.js +216 -0
- package/dist/tasks/bulk-translate-coordinator.d.ts +115 -0
- package/dist/tasks/bulk-translate-coordinator.js +708 -0
- package/dist/tasks/bulk-translate-doc-task.d.ts +142 -0
- package/dist/tasks/bulk-translate-doc-task.js +1000 -0
- package/dist/tasks/bulk-translate-janitor.d.ts +87 -0
- package/dist/tasks/bulk-translate-janitor.js +311 -0
- package/dist/tasks/translate-job-task.d.ts +51 -0
- package/dist/tasks/translate-job-task.js +154 -0
- package/dist/translate.d.ts +113 -0
- package/dist/translate.js +911 -0
- package/dist/translation-daily-spend-collection.d.ts +24 -0
- package/dist/translation-daily-spend-collection.js +133 -0
- package/dist/translation-rate-limits-collection.d.ts +30 -0
- package/dist/translation-rate-limits-collection.js +144 -0
- package/dist/types.d.ts +672 -0
- package/dist/types.js +1 -0
- package/dist/usage-collection.d.ts +14 -0
- package/dist/usage-collection.js +377 -0
- package/dist/views/BulkRunsHub/BatchRow.d.ts +32 -0
- package/dist/views/BulkRunsHub/BatchRow.js +1222 -0
- package/dist/views/BulkRunsHub/BucketRow.d.ts +62 -0
- package/dist/views/BulkRunsHub/BucketRow.js +982 -0
- package/dist/views/BulkRunsHub/BulkRunsHub.client.d.ts +18 -0
- package/dist/views/BulkRunsHub/BulkRunsHub.client.js +331 -0
- package/dist/views/BulkRunsHub/EmptyState.d.ts +6 -0
- package/dist/views/BulkRunsHub/EmptyState.js +64 -0
- package/dist/views/BulkRunsHub/FilterBar.d.ts +16 -0
- package/dist/views/BulkRunsHub/FilterBar.js +284 -0
- package/dist/views/BulkRunsHub/InFlightBanner.d.ts +14 -0
- package/dist/views/BulkRunsHub/InFlightBanner.js +59 -0
- package/dist/views/BulkRunsHub/StatusBadge.d.ts +64 -0
- package/dist/views/BulkRunsHub/StatusBadge.js +248 -0
- package/dist/views/BulkRunsHub/SummaryStrip.d.ts +22 -0
- package/dist/views/BulkRunsHub/SummaryStrip.js +249 -0
- package/dist/views/BulkRunsHub/bucket-grouping.d.ts +200 -0
- package/dist/views/BulkRunsHub/bucket-grouping.js +344 -0
- package/dist/views/BulkRunsHub/bucketFailureSummary.d.ts +9 -0
- package/dist/views/BulkRunsHub/bucketFailureSummary.js +36 -0
- package/dist/views/BulkRunsHub/dedupedStatusFetch.d.ts +5 -0
- package/dist/views/BulkRunsHub/dedupedStatusFetch.js +45 -0
- package/dist/views/BulkRunsHub/index.d.ts +17 -0
- package/dist/views/BulkRunsHub/index.js +80 -0
- package/dist/views/BulkRunsHub/urlFilters.d.ts +14 -0
- package/dist/views/BulkRunsHub/urlFilters.js +50 -0
- package/dist/views/BulkRunsHub/useBulkRunsList.d.ts +26 -0
- package/dist/views/BulkRunsHub/useBulkRunsList.js +204 -0
- package/dist/views/BulkRunsHub/useUrlFilters.d.ts +10 -0
- package/dist/views/BulkRunsHub/useUrlFilters.js +88 -0
- package/dist/views/TranslationHub/ActiveJobs.d.ts +6 -0
- package/dist/views/TranslationHub/ActiveJobs.js +320 -0
- package/dist/views/TranslationHub/AdvancedPanel.d.ts +17 -0
- package/dist/views/TranslationHub/AdvancedPanel.js +996 -0
- package/dist/views/TranslationHub/AlertBanner.d.ts +6 -0
- package/dist/views/TranslationHub/AlertBanner.js +568 -0
- package/dist/views/TranslationHub/AuditPanel.d.ts +6 -0
- package/dist/views/TranslationHub/AuditPanel.helpers.d.ts +44 -0
- package/dist/views/TranslationHub/AuditPanel.helpers.js +71 -0
- package/dist/views/TranslationHub/AuditPanel.js +1367 -0
- package/dist/views/TranslationHub/BulkTranslate.types.d.ts +242 -0
- package/dist/views/TranslationHub/BulkTranslate.types.js +36 -0
- package/dist/views/TranslationHub/BulkTranslateFailureDrawer.d.ts +19 -0
- package/dist/views/TranslationHub/BulkTranslateFailureDrawer.js +332 -0
- package/dist/views/TranslationHub/BulkTranslateMonitor.d.ts +28 -0
- package/dist/views/TranslationHub/BulkTranslateMonitor.js +305 -0
- package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.d.ts +3 -0
- package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.js +42 -0
- package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.d.ts +26 -0
- package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.js +95 -0
- package/dist/views/TranslationHub/BulkTranslatePreflightModal.d.ts +22 -0
- package/dist/views/TranslationHub/BulkTranslatePreflightModal.js +879 -0
- package/dist/views/TranslationHub/BulkTranslateTerminalCard.d.ts +29 -0
- package/dist/views/TranslationHub/BulkTranslateTerminalCard.js +445 -0
- package/dist/views/TranslationHub/BulkTranslateTrigger.d.ts +66 -0
- package/dist/views/TranslationHub/BulkTranslateTrigger.js +161 -0
- package/dist/views/TranslationHub/EditorRecentRunsPanel.d.ts +33 -0
- package/dist/views/TranslationHub/EditorRecentRunsPanel.js +290 -0
- package/dist/views/TranslationHub/Hub.client.d.ts +74 -0
- package/dist/views/TranslationHub/Hub.client.js +357 -0
- package/dist/views/TranslationHub/ModelCombobox.d.ts +14 -0
- package/dist/views/TranslationHub/ModelCombobox.js +415 -0
- package/dist/views/TranslationHub/PerCollectionConfig.d.ts +10 -0
- package/dist/views/TranslationHub/PerCollectionConfig.helpers.d.ts +16 -0
- package/dist/views/TranslationHub/PerCollectionConfig.helpers.js +19 -0
- package/dist/views/TranslationHub/PerCollectionConfig.js +759 -0
- package/dist/views/TranslationHub/SettingsRail.d.ts +11 -0
- package/dist/views/TranslationHub/SettingsRail.js +382 -0
- package/dist/views/TranslationHub/StatusStrip.d.ts +6 -0
- package/dist/views/TranslationHub/StatusStrip.js +451 -0
- package/dist/views/TranslationHub/UsageTable.d.ts +6 -0
- package/dist/views/TranslationHub/UsageTable.helpers.d.ts +69 -0
- package/dist/views/TranslationHub/UsageTable.helpers.js +49 -0
- package/dist/views/TranslationHub/UsageTable.js +1240 -0
- package/dist/views/TranslationHub/alertGrouping.d.ts +70 -0
- package/dist/views/TranslationHub/alertGrouping.js +99 -0
- package/dist/views/TranslationHub/index.d.ts +20 -0
- package/dist/views/TranslationHub/index.js +109 -0
- package/dist/views/TranslationHub/tabNavigation.d.ts +53 -0
- package/dist/views/TranslationHub/tabNavigation.js +74 -0
- package/dist/views/TranslationHub/terminalBannerVisibility.d.ts +33 -0
- package/dist/views/TranslationHub/terminalBannerVisibility.js +124 -0
- package/dist/views/TranslationHub/useBulkTranslateActive.d.ts +49 -0
- package/dist/views/TranslationHub/useBulkTranslateActive.js +251 -0
- package/dist/views/TranslationHub/useFocusTrap.d.ts +6 -0
- package/dist/views/TranslationHub/useFocusTrap.js +81 -0
- package/dist/views/TranslationHub/useTranslationHubUsageSummary.d.ts +77 -0
- package/dist/views/TranslationHub/useTranslationHubUsageSummary.js +267 -0
- package/dist/views/shared/EditorError.d.ts +97 -0
- package/dist/views/shared/EditorError.js +205 -0
- package/dist/views/shared/ModelCell.d.ts +18 -0
- package/dist/views/shared/ModelCell.js +31 -0
- package/dist/views/shared/docHref.d.ts +16 -0
- package/dist/views/shared/docHref.js +26 -0
- package/dist/views/shared/fetch-error-body.d.ts +25 -0
- package/dist/views/shared/fetch-error-body.js +42 -0
- package/dist/views/shared/filterPillStyle.d.ts +35 -0
- package/dist/views/shared/filterPillStyle.js +40 -0
- package/dist/views/shared/format.d.ts +75 -0
- package/dist/views/shared/format.js +131 -0
- package/package.json +141 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LanguageModel } from 'ai';
|
|
2
|
+
import type { TranslationProvider } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pricing entry used to compute `estimatedCostUsd`. Per-token cost in USD.
|
|
5
|
+
* Provider-specific tables are passed in by each wrapper factory; pass
|
|
6
|
+
* `undefined` to opt out of cost estimation.
|
|
7
|
+
*/
|
|
8
|
+
export type PricingPerToken = {
|
|
9
|
+
input: number;
|
|
10
|
+
output: number;
|
|
11
|
+
};
|
|
12
|
+
export type AISDKProviderInput = {
|
|
13
|
+
/** Pre-built `LanguageModel` from `@ai-sdk/<vendor>`'s factory. */
|
|
14
|
+
model: LanguageModel;
|
|
15
|
+
/** Model id for analytics + pricing lookup; mirrored on the provider object. */
|
|
16
|
+
modelId: string;
|
|
17
|
+
/** Optional. Skip to disable cost estimation. */
|
|
18
|
+
pricing?: PricingPerToken;
|
|
19
|
+
temperature?: number;
|
|
20
|
+
/** AI SDK's `maxOutputTokens`. Optional. */
|
|
21
|
+
maxOutputTokens?: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The shared core that all four built-in providers (openai, anthropic,
|
|
25
|
+
* gemini, custom) call into. Replaces ~1000 lines of per-provider parser
|
|
26
|
+
* + prompt + JSON-mode plumbing with a single `generateObject` call.
|
|
27
|
+
*
|
|
28
|
+
* Why this exists:
|
|
29
|
+
* - Each vendor's hand-rolled JSON parser had its own quirks (the
|
|
30
|
+
* Anthropic prefill bug that broke single-item requests is one of N).
|
|
31
|
+
* - `generateObject` enforces the response shape via tool-calling /
|
|
32
|
+
* structured-output, so the model literally cannot emit a malformed
|
|
33
|
+
* array. Schema validation happens before we see the data.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createAISDKProvider(input: AISDKProviderInput): TranslationProvider;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { generateObject, NoObjectGeneratedError } from 'ai';
|
|
2
|
+
import { buildSystemPrompt, buildUserMessage, estimateUsage, TranslateResponseSchema } from '../lib/translate-prompt.js';
|
|
3
|
+
const DEFAULT_TEMPERATURE = 0.3;
|
|
4
|
+
/**
|
|
5
|
+
* The shared core that all four built-in providers (openai, anthropic,
|
|
6
|
+
* gemini, custom) call into. Replaces ~1000 lines of per-provider parser
|
|
7
|
+
* + prompt + JSON-mode plumbing with a single `generateObject` call.
|
|
8
|
+
*
|
|
9
|
+
* Why this exists:
|
|
10
|
+
* - Each vendor's hand-rolled JSON parser had its own quirks (the
|
|
11
|
+
* Anthropic prefill bug that broke single-item requests is one of N).
|
|
12
|
+
* - `generateObject` enforces the response shape via tool-calling /
|
|
13
|
+
* structured-output, so the model literally cannot emit a malformed
|
|
14
|
+
* array. Schema validation happens before we see the data.
|
|
15
|
+
*/ export function createAISDKProvider(input) {
|
|
16
|
+
const temperature = input.temperature ?? DEFAULT_TEMPERATURE;
|
|
17
|
+
return {
|
|
18
|
+
model: input.modelId,
|
|
19
|
+
async translate (request) {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
const system = buildSystemPrompt(request);
|
|
22
|
+
const userMessage = buildUserMessage(request);
|
|
23
|
+
try {
|
|
24
|
+
const result = await generateObject({
|
|
25
|
+
model: input.model,
|
|
26
|
+
schema: TranslateResponseSchema,
|
|
27
|
+
system,
|
|
28
|
+
messages: [
|
|
29
|
+
{
|
|
30
|
+
role: 'user',
|
|
31
|
+
content: userMessage
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
temperature,
|
|
35
|
+
...input.maxOutputTokens ? {
|
|
36
|
+
maxOutputTokens: input.maxOutputTokens
|
|
37
|
+
} : {},
|
|
38
|
+
abortSignal: request.signal ?? undefined
|
|
39
|
+
});
|
|
40
|
+
const latencyMs = Date.now() - start;
|
|
41
|
+
const inputTokens = result.usage?.inputTokens ?? 0;
|
|
42
|
+
const outputTokens = result.usage?.outputTokens ?? 0;
|
|
43
|
+
return {
|
|
44
|
+
items: result.object.items,
|
|
45
|
+
usage: {
|
|
46
|
+
inputTokens,
|
|
47
|
+
outputTokens,
|
|
48
|
+
estimatedCostUsd: input.pricing ? inputTokens * input.pricing.input + outputTokens * input.pricing.output : undefined
|
|
49
|
+
},
|
|
50
|
+
model: input.modelId,
|
|
51
|
+
latencyMs
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// `NoObjectGeneratedError` carries partial usage data when the
|
|
55
|
+
// model spent tokens but emitted output that failed schema
|
|
56
|
+
// validation. Surface that so the per-locale failure persists
|
|
57
|
+
// accurate cost data, and include a snippet of the raw model
|
|
58
|
+
// output so operators can diagnose oversize inputs vs garbage
|
|
59
|
+
// output. The previous error message just bubbled the AI SDK's
|
|
60
|
+
// generic "could not parse" string with no clue about the cause.
|
|
61
|
+
if (NoObjectGeneratedError.isInstance(error)) {
|
|
62
|
+
const usage = error.usage;
|
|
63
|
+
const rawText = typeof error.text === 'string' ? error.text : '';
|
|
64
|
+
const headSnippet = rawText ? ` (model output head: ${JSON.stringify(rawText.slice(0, 200))}${rawText.length > 200 ? '…' : ''})` : '';
|
|
65
|
+
// Output-budget exhaustion is the dominant cause of schema-validation
|
|
66
|
+
// failures on Anthropic + AI SDK `generateObject` for translation
|
|
67
|
+
// batches: the model produces JSON until it hits `maxOutputTokens`,
|
|
68
|
+
// gets cut off mid-string, and the partial response fails Zod parse.
|
|
69
|
+
// Detect this by comparing observed outputTokens to the configured
|
|
70
|
+
// cap — outputs sitting at (or within ~5% of) the cap are truncation,
|
|
71
|
+
// not malformed output. Naming `maxTokens` and the concrete observed
|
|
72
|
+
// value collapses minutes of debugging down to "raise the knob".
|
|
73
|
+
const outputTokens = usage?.outputTokens ?? 0;
|
|
74
|
+
const cap = input.maxOutputTokens;
|
|
75
|
+
const lookedTruncated = !!cap && outputTokens > 0 && outputTokens >= cap * 0.95;
|
|
76
|
+
let hint = '';
|
|
77
|
+
if (lookedTruncated) {
|
|
78
|
+
hint = ` — output truncated at ${outputTokens} tokens` + (cap ? ` (maxOutputTokens=${cap})` : '') + `. Raise \`maxTokens\` on the provider config, or lower \`perCallCharLimit\` so each batch fits within the model's output budget.`;
|
|
79
|
+
} else {
|
|
80
|
+
const totalChars = request.items.reduce((sum, item)=>sum + item.text.length, 0);
|
|
81
|
+
if (totalChars > 10_000) {
|
|
82
|
+
hint = ` — input was ${totalChars} chars across ${request.items.length} items; if the model output got truncated, raise \`maxTokens\` or lower \`perCallCharLimit\`.`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw Object.assign(new Error(`[ai-translate] Schema validation failed for ${input.modelId}: model returned non-JSON output${headSnippet}${hint}`), {
|
|
86
|
+
cause: error,
|
|
87
|
+
usage: {
|
|
88
|
+
inputTokens: usage?.inputTokens ?? 0,
|
|
89
|
+
outputTokens
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
async estimate (request) {
|
|
97
|
+
return estimateUsage(request, input.pricing);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TranslationProvider } from '../types.js';
|
|
2
|
+
import { type PricingPerToken } from './ai-sdk-adapter.js';
|
|
3
|
+
export type AnthropicProviderOptions = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
temperature?: number;
|
|
8
|
+
/** Maps to the AI SDK `maxOutputTokens` setting. */
|
|
9
|
+
maxTokens?: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
13
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MODEL_PRICING: Record<string, PricingPerToken>;
|
|
16
|
+
/**
|
|
17
|
+
* Anthropic resolves an alias like `claude-haiku-4-5` to a dated id
|
|
18
|
+
* (`claude-haiku-4-5-20251001`). The pricing table is keyed by the alias,
|
|
19
|
+
* so strip a trailing `-YYYYMMDD` before lookup.
|
|
20
|
+
*/
|
|
21
|
+
export declare function lookupPricing(model: string): PricingPerToken | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to Anthropic.
|
|
24
|
+
*
|
|
25
|
+
* The previous implementation used a "JSON prefill" hack (`{"items":` as
|
|
26
|
+
* the assistant's pre-filled message) and concatenated the model's
|
|
27
|
+
* continuation. That broke for single-item requests on Haiku 4.5, which
|
|
28
|
+
* emitted an extra closing brace. `generateObject` enforces the response
|
|
29
|
+
* shape via tool-calling — the model literally cannot emit a stray brace.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createAnthropicProvider(options: AnthropicProviderOptions): TranslationProvider;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
2
|
+
import { createAISDKProvider } from './ai-sdk-adapter.js';
|
|
3
|
+
const DEFAULT_MODEL = 'claude-sonnet-4-6';
|
|
4
|
+
// Default output budget per translate call. History: 4096 truncated
|
|
5
|
+
// Haiku mid-response, 16384 was the 1.1.12 fix and held until a
|
|
6
|
+
// consumer using perCallCharLimit=50_000 hit it on Spanish/French
|
|
7
|
+
// (output expansion of 20-30% pushed legitimate outputs past 16k).
|
|
8
|
+
// 64_000 gives ~4x headroom over the largest output we have observed
|
|
9
|
+
// in production translations and sits within Claude 4.x per-request
|
|
10
|
+
// output ceilings via every upstream we route to. The cap is billed
|
|
11
|
+
// per actual output token used, so the unused headroom is free unless
|
|
12
|
+
// the model fills it. Consumers can still override via `maxTokens`.
|
|
13
|
+
const DEFAULT_MAX_TOKENS = 64_000;
|
|
14
|
+
/**
|
|
15
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
16
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
17
|
+
*/ export const MODEL_PRICING = {
|
|
18
|
+
'claude-opus-4-6': {
|
|
19
|
+
input: 15.0 / 1_000_000,
|
|
20
|
+
output: 75.0 / 1_000_000
|
|
21
|
+
},
|
|
22
|
+
'claude-sonnet-4-6': {
|
|
23
|
+
input: 3.0 / 1_000_000,
|
|
24
|
+
output: 15.0 / 1_000_000
|
|
25
|
+
},
|
|
26
|
+
'claude-haiku-4-5': {
|
|
27
|
+
input: 0.8 / 1_000_000,
|
|
28
|
+
output: 4.0 / 1_000_000
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Anthropic resolves an alias like `claude-haiku-4-5` to a dated id
|
|
33
|
+
* (`claude-haiku-4-5-20251001`). The pricing table is keyed by the alias,
|
|
34
|
+
* so strip a trailing `-YYYYMMDD` before lookup.
|
|
35
|
+
*/ export function lookupPricing(model) {
|
|
36
|
+
if (MODEL_PRICING[model]) return MODEL_PRICING[model];
|
|
37
|
+
const stripped = model.replace(/-\d{8}$/, '');
|
|
38
|
+
return MODEL_PRICING[stripped];
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Provider factory
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to Anthropic.
|
|
45
|
+
*
|
|
46
|
+
* The previous implementation used a "JSON prefill" hack (`{"items":` as
|
|
47
|
+
* the assistant's pre-filled message) and concatenated the model's
|
|
48
|
+
* continuation. That broke for single-item requests on Haiku 4.5, which
|
|
49
|
+
* emitted an extra closing brace. `generateObject` enforces the response
|
|
50
|
+
* shape via tool-calling — the model literally cannot emit a stray brace.
|
|
51
|
+
*/ export function createAnthropicProvider(options) {
|
|
52
|
+
const modelId = options.model ?? DEFAULT_MODEL;
|
|
53
|
+
const anthropic = createAnthropic({
|
|
54
|
+
apiKey: options.apiKey,
|
|
55
|
+
...options.baseURL ? {
|
|
56
|
+
baseURL: options.baseURL
|
|
57
|
+
} : {}
|
|
58
|
+
});
|
|
59
|
+
return createAISDKProvider({
|
|
60
|
+
model: anthropic(modelId),
|
|
61
|
+
modelId,
|
|
62
|
+
pricing: lookupPricing(modelId),
|
|
63
|
+
temperature: options.temperature,
|
|
64
|
+
maxOutputTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TranslationProvider } from '../types.js';
|
|
2
|
+
export type CustomProviderPricing = {
|
|
3
|
+
/** Cost per input token in USD. */
|
|
4
|
+
input: number;
|
|
5
|
+
/** Cost per output token in USD. */
|
|
6
|
+
output: number;
|
|
7
|
+
};
|
|
8
|
+
export type CustomProviderOptions = {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Base URL of the OpenAI-compatible endpoint
|
|
12
|
+
* (Together AI, Groq, vLLM, OpenRouter, etc).
|
|
13
|
+
*/
|
|
14
|
+
baseURL: string;
|
|
15
|
+
model: string;
|
|
16
|
+
/**
|
|
17
|
+
* Optional pricing override. The custom endpoint's vendor/model pair
|
|
18
|
+
* isn't known to the plugin, so consumers supply their own table when
|
|
19
|
+
* they want cost tracking.
|
|
20
|
+
*/
|
|
21
|
+
pricing?: CustomProviderPricing;
|
|
22
|
+
temperature?: number;
|
|
23
|
+
/** Maps to the AI SDK `maxOutputTokens` setting. */
|
|
24
|
+
maxTokens?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Friendly name for the endpoint (default: "custom"). Surfaces in
|
|
27
|
+
* AI SDK error messages when something goes wrong upstream.
|
|
28
|
+
*/
|
|
29
|
+
name?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to any
|
|
33
|
+
* OpenAI-compatible endpoint via `@ai-sdk/openai-compatible`. Drop-in
|
|
34
|
+
* replacement for the previous custom-provider implementation.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createCustomProvider(options: CustomProviderOptions): TranslationProvider;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
2
|
+
import { createAISDKProvider } from './ai-sdk-adapter.js';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Provider factory
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
/**
|
|
7
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to any
|
|
8
|
+
* OpenAI-compatible endpoint via `@ai-sdk/openai-compatible`. Drop-in
|
|
9
|
+
* replacement for the previous custom-provider implementation.
|
|
10
|
+
*/ export function createCustomProvider(options) {
|
|
11
|
+
const { model: modelId, pricing } = options;
|
|
12
|
+
const provider = createOpenAICompatible({
|
|
13
|
+
name: options.name ?? 'custom',
|
|
14
|
+
apiKey: options.apiKey,
|
|
15
|
+
baseURL: options.baseURL
|
|
16
|
+
});
|
|
17
|
+
return createAISDKProvider({
|
|
18
|
+
model: provider(modelId),
|
|
19
|
+
modelId,
|
|
20
|
+
pricing,
|
|
21
|
+
temperature: options.temperature,
|
|
22
|
+
maxOutputTokens: options.maxTokens
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TranslationProvider } from '../types.js';
|
|
2
|
+
import { type PricingPerToken } from './ai-sdk-adapter.js';
|
|
3
|
+
export type GeminiProviderOptions = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
temperature?: number;
|
|
7
|
+
/** Maps to the AI SDK `maxOutputTokens` setting. */
|
|
8
|
+
maxOutputTokens?: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
12
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MODEL_PRICING: Record<string, PricingPerToken>;
|
|
15
|
+
export declare function lookupPricing(model: string): PricingPerToken | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to Google's
|
|
18
|
+
* Gemini API. Uses `@ai-sdk/google`'s `createGoogleGenerativeAI`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createGeminiProvider(options: GeminiProviderOptions): TranslationProvider;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
2
|
+
import { createAISDKProvider } from './ai-sdk-adapter.js';
|
|
3
|
+
const DEFAULT_MODEL = 'gemini-2.5-flash';
|
|
4
|
+
// Default output budget per translate call. Without this the AI SDK
|
|
5
|
+
// inherits Google's per-request default (which has bitten consumers
|
|
6
|
+
// on long-form blog posts). 64_000 sits within Gemini 2.5 Flash and
|
|
7
|
+
// Pro output ceilings and is billed per actual use, so headroom is
|
|
8
|
+
// free. Consumers can override via `maxOutputTokens`.
|
|
9
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 64_000;
|
|
10
|
+
/**
|
|
11
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
12
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
13
|
+
*/ export const MODEL_PRICING = {
|
|
14
|
+
'gemini-2.5-pro': {
|
|
15
|
+
input: 1.25 / 1_000_000,
|
|
16
|
+
output: 10.0 / 1_000_000
|
|
17
|
+
},
|
|
18
|
+
'gemini-2.5-flash': {
|
|
19
|
+
input: 0.15 / 1_000_000,
|
|
20
|
+
output: 0.6 / 1_000_000
|
|
21
|
+
},
|
|
22
|
+
'gemini-2.0-flash': {
|
|
23
|
+
input: 0.1 / 1_000_000,
|
|
24
|
+
output: 0.4 / 1_000_000
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export function lookupPricing(model) {
|
|
28
|
+
return MODEL_PRICING[model];
|
|
29
|
+
}
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Provider factory
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/**
|
|
34
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to Google's
|
|
35
|
+
* Gemini API. Uses `@ai-sdk/google`'s `createGoogleGenerativeAI`.
|
|
36
|
+
*/ export function createGeminiProvider(options) {
|
|
37
|
+
const modelId = options.model ?? DEFAULT_MODEL;
|
|
38
|
+
const google = createGoogleGenerativeAI({
|
|
39
|
+
apiKey: options.apiKey
|
|
40
|
+
});
|
|
41
|
+
return createAISDKProvider({
|
|
42
|
+
model: google(modelId),
|
|
43
|
+
modelId,
|
|
44
|
+
pricing: lookupPricing(modelId),
|
|
45
|
+
temperature: options.temperature,
|
|
46
|
+
maxOutputTokens: options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function createMockProvider() {
|
|
2
|
+
return {
|
|
3
|
+
model: 'mock',
|
|
4
|
+
async translate (request) {
|
|
5
|
+
const start = Date.now();
|
|
6
|
+
const items = request.items.map((item)=>({
|
|
7
|
+
id: item.id,
|
|
8
|
+
text: `[${request.targetLocale}] ${item.text}`
|
|
9
|
+
}));
|
|
10
|
+
const totalChars = request.items.reduce((sum, item)=>sum + item.text.length, 0);
|
|
11
|
+
return {
|
|
12
|
+
items,
|
|
13
|
+
usage: {
|
|
14
|
+
inputTokens: totalChars,
|
|
15
|
+
outputTokens: totalChars
|
|
16
|
+
},
|
|
17
|
+
model: 'mock',
|
|
18
|
+
latencyMs: Date.now() - start
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
async estimate (request) {
|
|
22
|
+
const totalChars = request.items.reduce((sum, item)=>sum + item.text.length, 0);
|
|
23
|
+
return {
|
|
24
|
+
inputTokens: totalChars,
|
|
25
|
+
estimatedCostUsd: 0
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TranslationProvider } from '../types.js';
|
|
2
|
+
import { type PricingPerToken } from './ai-sdk-adapter.js';
|
|
3
|
+
export type OpenAIProviderOptions = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
temperature?: number;
|
|
8
|
+
/** Maps to the AI SDK `maxOutputTokens` setting. */
|
|
9
|
+
maxTokens?: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
13
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MODEL_PRICING: Record<string, PricingPerToken>;
|
|
16
|
+
/**
|
|
17
|
+
* OpenAI returns dated model ids (`gpt-4o-mini-2024-07-18`). Strip a
|
|
18
|
+
* trailing `-YYYY-MM-DD` suffix before pricing lookup.
|
|
19
|
+
*/
|
|
20
|
+
export declare function lookupPricing(model: string): PricingPerToken | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to OpenAI.
|
|
23
|
+
* Public API is unchanged from the pre-AI-SDK implementation — consumers
|
|
24
|
+
* pass `{ apiKey, model }` and get back a `TranslationProvider`. Internals
|
|
25
|
+
* delegate to `createAISDKProvider`, which uses `generateObject` and
|
|
26
|
+
* eliminates manual JSON parsing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createOpenAIProvider(options: OpenAIProviderOptions): TranslationProvider;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
2
|
+
import { createAISDKProvider } from './ai-sdk-adapter.js';
|
|
3
|
+
const DEFAULT_MODEL = 'gpt-4o';
|
|
4
|
+
// Default output budget per translate call. The AI SDK's
|
|
5
|
+
// `generateObject` has no built-in cap, so without this the upstream's
|
|
6
|
+
// own default applies (commonly 4096 on GPT-4o) and large batches
|
|
7
|
+
// truncate mid-JSON, producing the misleading "non-JSON output"
|
|
8
|
+
// error. 64_000 sits within GPT-4o / GPT-4.1 family output ceilings
|
|
9
|
+
// and is billed per actual use, so headroom is free. Consumers can
|
|
10
|
+
// override via `maxTokens`.
|
|
11
|
+
const DEFAULT_MAX_TOKENS = 64_000;
|
|
12
|
+
/**
|
|
13
|
+
* Per-token pricing in USD. Updated as of April 2026.
|
|
14
|
+
* Unknown models return undefined for cost estimates — not an error.
|
|
15
|
+
*/ export const MODEL_PRICING = {
|
|
16
|
+
'gpt-4o': {
|
|
17
|
+
input: 2.5 / 1_000_000,
|
|
18
|
+
output: 10.0 / 1_000_000
|
|
19
|
+
},
|
|
20
|
+
'gpt-4o-mini': {
|
|
21
|
+
input: 0.15 / 1_000_000,
|
|
22
|
+
output: 0.6 / 1_000_000
|
|
23
|
+
},
|
|
24
|
+
'gpt-4.1': {
|
|
25
|
+
input: 2.0 / 1_000_000,
|
|
26
|
+
output: 8.0 / 1_000_000
|
|
27
|
+
},
|
|
28
|
+
'gpt-4.1-mini': {
|
|
29
|
+
input: 0.4 / 1_000_000,
|
|
30
|
+
output: 1.6 / 1_000_000
|
|
31
|
+
},
|
|
32
|
+
'gpt-4.1-nano': {
|
|
33
|
+
input: 0.1 / 1_000_000,
|
|
34
|
+
output: 0.4 / 1_000_000
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* OpenAI returns dated model ids (`gpt-4o-mini-2024-07-18`). Strip a
|
|
39
|
+
* trailing `-YYYY-MM-DD` suffix before pricing lookup.
|
|
40
|
+
*/ export function lookupPricing(model) {
|
|
41
|
+
if (MODEL_PRICING[model]) return MODEL_PRICING[model];
|
|
42
|
+
const stripped = model.replace(/-\d{4}-\d{2}-\d{2}$/, '');
|
|
43
|
+
return MODEL_PRICING[stripped];
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Provider factory
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
/**
|
|
49
|
+
* Builds an AI-SDK-backed `TranslationProvider` that talks to OpenAI.
|
|
50
|
+
* Public API is unchanged from the pre-AI-SDK implementation — consumers
|
|
51
|
+
* pass `{ apiKey, model }` and get back a `TranslationProvider`. Internals
|
|
52
|
+
* delegate to `createAISDKProvider`, which uses `generateObject` and
|
|
53
|
+
* eliminates manual JSON parsing.
|
|
54
|
+
*/ export function createOpenAIProvider(options) {
|
|
55
|
+
const modelId = options.model ?? DEFAULT_MODEL;
|
|
56
|
+
const openai = createOpenAI({
|
|
57
|
+
apiKey: options.apiKey,
|
|
58
|
+
...options.baseURL ? {
|
|
59
|
+
baseURL: options.baseURL
|
|
60
|
+
} : {}
|
|
61
|
+
});
|
|
62
|
+
return createAISDKProvider({
|
|
63
|
+
model: openai(modelId),
|
|
64
|
+
modelId,
|
|
65
|
+
pricing: lookupPricing(modelId),
|
|
66
|
+
temperature: options.temperature,
|
|
67
|
+
maxOutputTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Access, GlobalConfig } from 'payload';
|
|
2
|
+
export declare const DEFAULT_SETTINGS_GLOBAL_SLUG = "translation-settings";
|
|
3
|
+
/**
|
|
4
|
+
* Per-collection (or global) settings row stored under
|
|
5
|
+
* `translation-settings.perCollection`. Lets admins configure each
|
|
6
|
+
* translatable surface independently. **AUTOMATION ONLY** — none of
|
|
7
|
+
* these fields gate the manual Translate… dialog or per-field button.
|
|
8
|
+
* Editors retain full manual access to every tracked surface; this
|
|
9
|
+
* layer narrows what `after-change` fan-out does.
|
|
10
|
+
*
|
|
11
|
+
* - `enabled` — when `false`, the auto-translate after-change hook
|
|
12
|
+
* skips this surface entirely. Manual Translate still works.
|
|
13
|
+
* - `autoOnPublish` — when `false`, the on-publish trigger skips this
|
|
14
|
+
* surface. Manual Translate still works. Effectively a synonym for
|
|
15
|
+
* `enabled: false` today; both surface as `skipAutoOnPublish: true`
|
|
16
|
+
* in `effective-locales`. Kept distinct in the field schema so
|
|
17
|
+
* admins can express intent (collection-disabled vs auto-disabled).
|
|
18
|
+
* - `targetLocalesOverride` — restrict which target locales auto-
|
|
19
|
+
* translate. Empty / unset = inherit from site-wide
|
|
20
|
+
* `enabledTargetLocales`. A locale must be in BOTH lists to fan out.
|
|
21
|
+
* - `excludedFieldPaths` — field paths excluded from translation for
|
|
22
|
+
* this surface. **Applies to BOTH manual and automation paths** —
|
|
23
|
+
* distinct from the automation-only `enabled` / `autoOnPublish`
|
|
24
|
+
* flags above. The admin decision "never translate `meta.description`
|
|
25
|
+
* on posts" is global; it would be surprising if Manual Translate…
|
|
26
|
+
* silently ignored it. Empty / unset = translate every auto-resolved
|
|
27
|
+
* field (back-compat with pre-D6 deployments).
|
|
28
|
+
* - `translateSlug` — opt-in for slug translation. Defaults to false
|
|
29
|
+
* because the plugin's `excludeFields` config typically lists
|
|
30
|
+
* `'slug'` to prevent accidental per-locale URL churn. When `true`
|
|
31
|
+
* AND the consumer's slug field is `localized: true` on the
|
|
32
|
+
* collection schema, the slug becomes translatable for this
|
|
33
|
+
* surface. Applies to BOTH manual and automation paths.
|
|
34
|
+
*/
|
|
35
|
+
export type PerCollectionSettings = {
|
|
36
|
+
slug: string;
|
|
37
|
+
enabled?: boolean | null;
|
|
38
|
+
autoOnPublish?: boolean | null;
|
|
39
|
+
targetLocalesOverride?: string[] | null;
|
|
40
|
+
excludedFieldPaths?: string[] | null;
|
|
41
|
+
translateSlug?: boolean | null;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Auto-registered global that lets admins manage translation runtime
|
|
45
|
+
* settings without editing `payload.config.ts` and restarting the
|
|
46
|
+
* server. Carries two responsibilities:
|
|
47
|
+
*
|
|
48
|
+
* 1. **Active provider selection** — when the consumer configured a
|
|
49
|
+
* `providers` map, each entry becomes a select option here. The
|
|
50
|
+
* translate path resolves the active provider at request time (see
|
|
51
|
+
* `resolveProvider` in `api.ts`). Hidden when no `providers` map is
|
|
52
|
+
* configured (single-provider consumer).
|
|
53
|
+
*
|
|
54
|
+
* 2. **Per-locale auto-translate toggle** — admins can opt locales out
|
|
55
|
+
* of the on-publish auto-translate hook without losing the ability
|
|
56
|
+
* to manually translate to those locales via the Translate button.
|
|
57
|
+
* Empty / unset = "all enabled" (back-compat).
|
|
58
|
+
*
|
|
59
|
+
* Read/write access defaults to admin-only: these settings affect
|
|
60
|
+
* operational cost and translation coverage, so editors shouldn't
|
|
61
|
+
* silently change them. Override via `settings.access`.
|
|
62
|
+
*/
|
|
63
|
+
export type TranslationSettingsConfig = {
|
|
64
|
+
/** Master switch. Defaults to `true` when targetLocales is configured. */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
/** Override the auto-registered global slug. */
|
|
67
|
+
globalSlug?: string;
|
|
68
|
+
/** Override the default admin-only read/update access. */
|
|
69
|
+
access?: {
|
|
70
|
+
read?: Access;
|
|
71
|
+
update?: Access;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
export declare function createSettingsGlobal(providerKeys: string[], targetLocales: string[], options?: TranslationSettingsConfig, trackedSurfaces?: string[]): GlobalConfig;
|