Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
374
scripts/docs-i18n/translator.go
Normal file
374
scripts/docs-i18n/translator.go
Normal file
@@ -0,0 +1,374 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
translateMaxAttempts = 3
|
||||
translateBaseDelay = 15 * time.Second
|
||||
defaultPromptTimeout = 2 * time.Minute
|
||||
defaultCommandWaitDelay = 15 * time.Second
|
||||
envDocsI18nPromptTimeout = "OPENCLAW_DOCS_I18N_PROMPT_TIMEOUT"
|
||||
envDocsI18nCommandWaitDelay = "OPENCLAW_DOCS_I18N_COMMAND_WAIT_DELAY"
|
||||
envDocsI18nCodexExecutable = "OPENCLAW_DOCS_I18N_CODEX_EXECUTABLE"
|
||||
)
|
||||
|
||||
var errEmptyTranslation = errors.New("empty translation")
|
||||
|
||||
var translateRetryDelay = func(attempt int) time.Duration {
|
||||
return translateBaseDelay * time.Duration(attempt)
|
||||
}
|
||||
|
||||
type CodexTranslator struct {
|
||||
systemPrompt string
|
||||
exactGlossaryMappings map[string]string
|
||||
thinking string
|
||||
runPrompt codexPromptRunner
|
||||
}
|
||||
|
||||
type docsTranslator interface {
|
||||
Translate(context.Context, string, string, string) (string, error)
|
||||
TranslateRaw(context.Context, string, string, string) (string, error)
|
||||
Close()
|
||||
}
|
||||
|
||||
type docsTranslatorFactory func(string, string, []GlossaryEntry, string) (docsTranslator, error)
|
||||
|
||||
type codexPromptRunner func(context.Context, codexPromptRequest) (string, error)
|
||||
|
||||
type codexPromptRequest struct {
|
||||
SystemPrompt string
|
||||
Message string
|
||||
Model string
|
||||
Thinking string
|
||||
}
|
||||
|
||||
func NewCodexTranslator(srcLang, tgtLang string, glossary []GlossaryEntry, thinking string) (*CodexTranslator, error) {
|
||||
return &CodexTranslator{
|
||||
systemPrompt: translationPrompt(srcLang, tgtLang, glossary),
|
||||
exactGlossaryMappings: exactGlossaryMappings(glossary),
|
||||
thinking: normalizeThinking(thinking),
|
||||
runPrompt: runCodexExecPrompt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) Translate(ctx context.Context, text, srcLang, tgtLang string) (string, error) {
|
||||
return t.translate(ctx, text, t.translateMasked)
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) TranslateRaw(ctx context.Context, text, srcLang, tgtLang string) (string, error) {
|
||||
return t.translate(ctx, text, t.translateRaw)
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) translate(ctx context.Context, text string, run func(context.Context, string) (string, error)) (string, error) {
|
||||
prefix, core, suffix := splitWhitespace(text)
|
||||
if core == "" {
|
||||
return text, nil
|
||||
}
|
||||
if translated, ok := t.exactGlossaryMappings[core]; ok {
|
||||
return prefix + translated + suffix, nil
|
||||
}
|
||||
translated, err := t.translateWithRetry(ctx, func(ctx context.Context) (string, error) {
|
||||
return run(ctx, core)
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return prefix + translated + suffix, nil
|
||||
}
|
||||
|
||||
func exactGlossaryMappings(glossary []GlossaryEntry) map[string]string {
|
||||
mappings := map[string]string{}
|
||||
for _, entry := range glossary {
|
||||
source := strings.TrimSpace(entry.Source)
|
||||
target := strings.TrimSpace(entry.Target)
|
||||
if source == "" || target == "" {
|
||||
continue
|
||||
}
|
||||
mappings[source] = target
|
||||
}
|
||||
return mappings
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) translateWithRetry(ctx context.Context, run func(context.Context) (string, error)) (string, error) {
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < translateMaxAttempts; attempt++ {
|
||||
translated, err := run(ctx)
|
||||
if err == nil {
|
||||
return translated, nil
|
||||
}
|
||||
if !isRetryableTranslateError(err) {
|
||||
return "", err
|
||||
}
|
||||
lastErr = err
|
||||
if attempt+1 < translateMaxAttempts {
|
||||
delay := translateRetryDelay(attempt + 1)
|
||||
if err := sleepWithContext(ctx, delay); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", lastErr
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) translateMasked(ctx context.Context, core string) (string, error) {
|
||||
state := NewPlaceholderState(core)
|
||||
placeholders := make([]string, 0, 8)
|
||||
mapping := map[string]string{}
|
||||
masked := maskMarkdown(core, state.Next, &placeholders, mapping)
|
||||
resText, err := t.prompt(ctx, masked)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
translated := stripCodexI18nInputWrappers(strings.TrimSpace(resText))
|
||||
if translated == "" {
|
||||
return "", errEmptyTranslation
|
||||
}
|
||||
if err := validatePlaceholders(translated, placeholders); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return unmaskMarkdown(translated, placeholders, mapping), nil
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) translateRaw(ctx context.Context, core string) (string, error) {
|
||||
resText, err := t.prompt(ctx, core)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
translated := stripCodexI18nInputWrappers(strings.TrimSpace(resText))
|
||||
if translated == "" {
|
||||
return "", errEmptyTranslation
|
||||
}
|
||||
return translated, nil
|
||||
}
|
||||
|
||||
func stripCodexI18nInputWrappers(text string) string {
|
||||
replacer := strings.NewReplacer(
|
||||
"<openclaw_docs_i18n_input>", "",
|
||||
"</openclaw_docs_i18n_input>", "",
|
||||
)
|
||||
return strings.TrimSpace(replacer.Replace(text))
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) prompt(ctx context.Context, message string) (string, error) {
|
||||
if t.runPrompt == nil {
|
||||
return "", errors.New("codex prompt runner unavailable")
|
||||
}
|
||||
promptCtx, cancel := context.WithTimeout(ctx, docsI18nPromptTimeout())
|
||||
defer cancel()
|
||||
return t.runPrompt(promptCtx, codexPromptRequest{
|
||||
SystemPrompt: t.systemPrompt,
|
||||
Message: message,
|
||||
Model: docsI18nModel(),
|
||||
Thinking: t.thinking,
|
||||
})
|
||||
}
|
||||
|
||||
func isRetryableTranslateError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
|
||||
return false
|
||||
}
|
||||
if errors.Is(err, errEmptyTranslation) {
|
||||
return true
|
||||
}
|
||||
message := strings.ToLower(err.Error())
|
||||
if strings.Contains(message, "authentication failed") || strings.Contains(message, "invalid_api_key") || strings.Contains(message, "api key") {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(message, "placeholder missing") ||
|
||||
strings.Contains(message, "rate limit") ||
|
||||
strings.Contains(message, "429") ||
|
||||
strings.Contains(message, "500") ||
|
||||
strings.Contains(message, "502") ||
|
||||
strings.Contains(message, "503") ||
|
||||
strings.Contains(message, "504") ||
|
||||
strings.Contains(message, "temporarily unavailable") ||
|
||||
strings.Contains(message, "connection reset") ||
|
||||
strings.Contains(message, "stream")
|
||||
}
|
||||
|
||||
func runCodexExecPrompt(ctx context.Context, req codexPromptRequest) (string, error) {
|
||||
outputFile, err := os.CreateTemp("", "openclaw-docs-i18n-codex-*.txt")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
outputPath := outputFile.Name()
|
||||
_ = outputFile.Close()
|
||||
defer os.Remove(outputPath)
|
||||
|
||||
codexHomeBase, err := isolatedCodexHomeBase()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
codexHome, err := os.MkdirTemp(codexHomeBase, "codex-home-*")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer os.RemoveAll(codexHome)
|
||||
if err := writeCodexAuthFile(codexHome); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"exec",
|
||||
"--model", req.Model,
|
||||
"-c", fmt.Sprintf("model_reasoning_effort=%q", normalizeThinking(req.Thinking)),
|
||||
"-c", `service_tier="fast"`,
|
||||
"--sandbox", "read-only",
|
||||
"--ignore-rules",
|
||||
"--skip-git-repo-check",
|
||||
"--output-last-message", outputPath,
|
||||
"-",
|
||||
}
|
||||
command := exec.CommandContext(ctx, docsCodexExecutable(), args...)
|
||||
configureCodexPromptCommand(command)
|
||||
command.Stdin = strings.NewReader(buildCodexTranslationPrompt(req.SystemPrompt, req.Message))
|
||||
command.Env = append(os.Environ(), "CODEX_HOME="+codexHome)
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
command.Stdout = &stdout
|
||||
command.Stderr = &stderr
|
||||
if err := command.Run(); err != nil {
|
||||
if translated, readErr := readCodexOutputLastMessage(outputPath); readErr == nil {
|
||||
return translated, nil
|
||||
}
|
||||
return "", fmt.Errorf("codex exec failed: %w (%s)", err, previewCommandOutput(stdout.String(), stderr.String()))
|
||||
}
|
||||
|
||||
return readCodexOutputLastMessage(outputPath)
|
||||
}
|
||||
|
||||
func readCodexOutputLastMessage(outputPath string) (string, error) {
|
||||
data, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
translated := strings.TrimSpace(string(data))
|
||||
if translated == "" {
|
||||
return "", errEmptyTranslation
|
||||
}
|
||||
return translated, nil
|
||||
}
|
||||
|
||||
func writeCodexAuthFile(codexHome string) error {
|
||||
apiKey := strings.TrimSpace(os.Getenv("OPENAI_API_KEY"))
|
||||
if apiKey == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := json.Marshal(map[string]string{
|
||||
"auth_mode": "apikey",
|
||||
"OPENAI_API_KEY": apiKey,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(filepath.Join(codexHome, "auth.json"), append(data, '\n'), 0o600)
|
||||
}
|
||||
|
||||
func isolatedCodexHomeBase() (string, error) {
|
||||
cacheDir, err := os.UserCacheDir()
|
||||
if err != nil || strings.TrimSpace(cacheDir) == "" {
|
||||
homeDir, homeErr := os.UserHomeDir()
|
||||
if homeErr != nil {
|
||||
return "", err
|
||||
}
|
||||
cacheDir = filepath.Join(homeDir, ".cache")
|
||||
}
|
||||
base := filepath.Join(cacheDir, "openclaw-docs-i18n")
|
||||
if err := os.MkdirAll(base, 0o700); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base, nil
|
||||
}
|
||||
|
||||
func docsCodexExecutable() string {
|
||||
if executable := strings.TrimSpace(os.Getenv(envDocsI18nCodexExecutable)); executable != "" {
|
||||
return executable
|
||||
}
|
||||
return "codex"
|
||||
}
|
||||
|
||||
func buildCodexTranslationPrompt(systemPrompt, message string) string {
|
||||
return strings.TrimSpace(systemPrompt) + "\n\n" +
|
||||
"Translate the exact input below. Return only the translated text, with no code fences, no tool calls, no reasoning, and no commentary.\n\n" +
|
||||
"<openclaw_docs_i18n_input>\n" +
|
||||
message +
|
||||
"\n</openclaw_docs_i18n_input>\n"
|
||||
}
|
||||
|
||||
func previewCommandOutput(stdout, stderr string) string {
|
||||
combined := strings.TrimSpace(strings.Join([]string{stdout, stderr}, "\n"))
|
||||
if combined == "" {
|
||||
return "no output"
|
||||
}
|
||||
combined = strings.Join(strings.Fields(combined), " ")
|
||||
const (
|
||||
limit = 1200
|
||||
headLength = 300
|
||||
tailLength = 800
|
||||
)
|
||||
if len(combined) <= limit {
|
||||
return combined
|
||||
}
|
||||
// Codex prints API failures after its header and prompt, so the tail carries the actionable error.
|
||||
return combined[:headLength] + " ... [truncated] ... " + combined[len(combined)-tailLength:]
|
||||
}
|
||||
|
||||
func sleepWithContext(ctx context.Context, delay time.Duration) error {
|
||||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-timer.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *CodexTranslator) Close() {}
|
||||
|
||||
func normalizeThinking(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "low", "medium", "high", "xhigh":
|
||||
return strings.ToLower(strings.TrimSpace(value))
|
||||
default:
|
||||
return "high"
|
||||
}
|
||||
}
|
||||
|
||||
func docsI18nPromptTimeout() time.Duration {
|
||||
value := strings.TrimSpace(os.Getenv(envDocsI18nPromptTimeout))
|
||||
if value == "" {
|
||||
return defaultPromptTimeout
|
||||
}
|
||||
parsed, err := time.ParseDuration(value)
|
||||
if err != nil || parsed <= 0 {
|
||||
return defaultPromptTimeout
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func docsI18nCommandWaitDelay() time.Duration {
|
||||
value := strings.TrimSpace(os.Getenv(envDocsI18nCommandWaitDelay))
|
||||
if value == "" {
|
||||
return defaultCommandWaitDelay
|
||||
}
|
||||
parsed, err := time.ParseDuration(value)
|
||||
if err != nil || parsed <= 0 {
|
||||
return defaultCommandWaitDelay
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
Reference in New Issue
Block a user