{"owner":"nextai-translator","repo":"bob-plugin-openai-translator","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":4512,"categories":["root-instruction","project-spec"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md","docs/architecture.md"],"skills":{"AGENTS.md":"# Coding Agent Instructions\n\n## Bob boundary\n\nThe shipped plugin runs in Bob's JavaScriptCore host, not Node.js or a browser. Development tooling may use Node.js or browser APIs, but runtime code is limited to JavaScript built-ins, Bob globals, and bundled pure JavaScript.\n\nBob's settings form is static and space-constrained. Design it around the person configuring the plugin, not the adapter structure.\n\nBob's installed behavior is the source of truth when it disagrees with documentation, type declarations, or assumptions from other JavaScript runtimes. In particular:\n\n- Do not assume a callback-based Bob API also returns a Promise unless that behavior has been observed in Bob.\n- Preserve Bob field names that look unusual or misspelled when the runtime contract uses them.\n- Verify installation and update behavior with the copied plugin metadata, not merely the archive contents.\n\n## Product defaults\n\nUse these defaults until a concrete user need or provider contract justifies revisiting them. When evidence does not determine the user-facing behavior, present the specific tradeoff to the maintainer before changing it.\n\n- Keep the common setup to API Key, model, and an optional complete API URL. Prefer deriving provider, protocol, Base URL, and API Path internally; add another setting only when a real service cannot otherwise be configured clearly.\n- Use \"OpenAI 兼容 API\" as the user-facing category for gateways, proxies, and services exposing `/responses` or `/chat/completions`. Name individual services in the manual only when they provide a useful configuration example or behave differently.\n- Use raw model IDs as model labels by default. Add qualifiers only when they resolve a real ambiguity, not to convey provider branding, performance tiers, or marketing claims.\n- Reasoning currently offers the model default and the lowest or disabled setting. Expand it only when a demonstrated translation use case justifies the additional choice.\n- Temperature is currently omitted because supported model families do not share a stable sampling contract. Reintroduce it only with evidence for coherent behavior and a clear user benefit.\n- The system prompt changes the task, such as translation to polishing. The user prompt refines each input within that task. Keep both defaults, placeholders, and keyword insertion editable.\n- Treat saved-setting compatibility and migration as release decisions. If a change requires choosing between a clean break and a migration, confirm the intended release scope instead of inferring it from the current version.\n\n`public/info.json` is Chinese-first; common technical names may remain in English. Describe user capabilities rather than adapter mechanics, omit context Bob already displays, keep descriptions concise without trailing sentence punctuation, and link detailed guidance to the exact configuration-manual heading.\n\n## Architecture tradeoffs\n\n- Isolate provider wire differences while sharing the Bob request lifecycle. Direct adapters are preferred at the current scale; reconsider SDKs or a broader provider abstraction only when they reduce demonstrated complexity and remain compatible with JavaScriptCore.\n- Add model controls from current official provider evidence. For unknown models and partially compatible APIs, omit optional controls rather than infer support.\n- A configured non-Azure API URL currently uses an OpenAI-compatible wire format. Verified official MiniMax hosts keep the MiniMax codec because their stream semantics differ. Supporting another native-provider proxy format is a product choice, not a URL-detection shortcut.\n- Validate compatible services with a small generation request because `/models` is not a reliable cross-service contract.\n- Preserve a real SSE parser: line splitting does not handle arbitrary chunk boundaries or multiline events.\n- Evaluate performance through local selection, request construction, parsing, and bundle size. Network latency does not establish an architecture improvement.\n- Route failures through Bob's supported completion callback with a useful `ServiceError.message`. Keep diagnostic logs identifiable by the plugin identifier without logging credentials or request bodies.\n\n## Documentation boundaries\n\n- `README.md` is the concise Chinese installation and configuration entry point.\n- The Chinese and English configuration manuals own detailed user guidance.\n- `docs/architecture.md` owns rationale, source coverage, rejected alternatives, and performance evidence.\n- `.github/contributing.md` is for human contributors arriving without repository context.\n\nLink to exact manual sections instead of repeating endpoint lists or advanced settings. Keep both languages, Bob metadata, runtime defaults, and tests behaviorally aligned.\n\nSort unordered links, examples, mappings, and reference collections by their displayed label or value. Preserve task, navigation, and lifecycle order when sequence carries meaning.\n\n## Validation limits\n\nStatic checks cannot prove behavior inside Bob. Runtime changes need a packaged-plugin smoke test covering settings rendering, provider validation, one streaming translation, and one non-streaming translation.\n\nThe current Bob release ignores plugin packages whose version is not newer than the installed copy. Keep the repository version unchanged during development, and require the generated archive version to be proven newer than the installed release but older than the next stable release. Verify the copied metadata after opening the package because installation completes asynchronously.\n\nLive-provider probes are opt-in and use only credentials explicitly supplied for that run. Never discover credentials from local files or credential stores.\n","docs/architecture.md":"# Architecture\n\nLast verified: 2026-07-23.\n\n## Runtime boundary\n\nBob runs plugins in JavaScriptCore, not Node.js or a browser. Runtime code may use JavaScript built-ins, Bob APIs, and bundled pure JavaScript only. The build produces one CommonJS `main.js`; Node.js is limited to build and test scripts.\n\nThe runtime path is intentionally small:\n\n```text\n$option\n  -> parseOptions()\n  -> resolveModelControls()\n  -> provider codec\n  -> shared $http transport\n  -> Bob stream/completion callbacks\n```\n\n- `src/main.ts` is the Bob entry point.\n- `src/config.ts` parses and freezes one configuration object, derives the provider, and rejects invalid complete API URLs.\n- `src/utils/model-capabilities.ts` owns the curated model catalog and model-specific reasoning mappings.\n- `src/adapter/*.ts` owns provider URL, authentication, wire request, wire response, validation, and stream event shapes.\n- `src/adapter/base.ts` owns cancellation, network lifecycle, and exactly-once completion.\n- `src/utils/sse.ts` owns bounded SSE parsing independently of provider capability rules.\n\nAdapters never read `$option`. Provider codecs receive a validated configuration and do not know how Bob stores options.\n\n## Configuration contract\n\nBob's public option schema provides static `text` and `menu` fields. It does not expose a documented conditional-field mechanism. The plugin therefore keeps the common path short instead of exposing every internal adapter choice.\n\nThe current configuration uses these decisions:\n\n- The default OpenAI path parses and runs when Bob supplies only an API Key. Runtime defaults cover model, streaming, and reasoning.\n- Provider is derived rather than user-selected. With no API URL, the model selects the official OpenAI, Gemini, or MiniMax adapter. With an API URL, Azure hosts and paths select Azure OpenAI, verified MiniMax official hosts retain the MiniMax stream codec, and other URLs use the OpenAI-compatible adapter.\n- API URL is optional and complete. The `/responses` or `/chat/completions` suffix selects the protocol without separate Base URL, path, or protocol fields.\n- Temperature is absent from the UI and every request. Provider defaults avoid invalid parameters as model sampling contracts evolve.\n- Reasoning has two choices. Default sends no control. Disable maps to the lowest verified model-specific setting; models without a verified mapping receive no control.\n- Editable System Prompt and User Prompt defaults preserve their distinct roles: the system prompt defines purpose, while the user prompt shapes each input within that purpose. Both support `$text`, `$sourceLang`, and `$targetLang`.\n- The default system prompt starts with the translation role and explicitly prevents instruction-like source text from becoming a command. The raw source remains a separate user message.\n- Menu values are case-insensitively sorted by `value`; the `custom` model entry is the only fixed first item.\n\n## Provider contracts\n\n| Provider | Protocol | Authentication | Validation |\n| --- | --- | --- | --- |\n| Azure OpenAI | Responses or Chat Completions | `api-key` header | Minimal generation request |\n| Gemini | GenerateContent | `x-goog-api-key` header | Model listing |\n| MiniMax | Chat Completions | Bearer token | Minimal generation request |\n| OpenAI | Responses | Bearer token | `GET /v1/models` |\n| OpenAI Compatible | Responses or Chat Completions | Bearer token | Minimal generation request |\n\nProvider dispatch is an exhaustive TypeScript switch. A new wire provider requires one union member, one provider definition, one codec, a derivation rule, and contract tests. No user-facing provider menu, dependency-injection container, or secondary class hierarchy is needed.\n\n## Model controls\n\n`resolveModelControls(provider, model, mode)` is the only runtime capability resolver.\n\nDefault always omits the provider control.\n\nOnly exact model IDs with a current provider contract receive a control:\n\n| Model ID | Disable |\n| --- | --- |\n| `gemini-2.5-flash`, `gemini-2.5-flash-lite` | thinking budget `0` |\n| `gemini-2.5-pro` | thinking budget `128` |\n| `gemini-3-flash-preview`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.6-flash` | thinking level `minimal` |\n| `gemini-3-pro-preview`, `gemini-3.1-pro-preview` | thinking level `low` |\n| `gpt-5` | `minimal` |\n| `gpt-5.3-codex` | `low` |\n| `gpt-5.4-mini`, `gpt-5.6`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra` | `none` |\n| `gpt-5-pro` | `high` |\n| `MiniMax-M3` | thinking `disabled` |\n| Any other ID | omitted |\n\nRequest codecs translate the normalized result into `reasoning`, `reasoning_effort`, `thinkingConfig`, or `thinking`. Capability code does not construct transport payloads.\n\nMiniMax requests set `reasoning_split` so reasoning does not enter the translated text. Its documented cumulative stream content is converted back to deltas before Bob callbacks.\n\nMiniMax validation disables thinking and limits output for M3. It does not cap M2.x output because those models cannot disable thinking, and a short limit can end the response before translated content appears.\n\nGemini uses stateless `generateContent` and `streamGenerateContent` requests because each Bob translation is one independent generation. The Interactions API's stateful and agentic lifecycle is not needed here.\n\nTo add a curated model:\n\n1. Add its ID and provider to `MODEL_CATALOG` in sorted order.\n2. Add an exact capability entry only when current provider documentation verifies its parameter contract.\n3. Add the same menu entry to `public/info.json`.\n4. Add or update capability, provider-body, and metadata tests.\n\nThe metadata test fails if the menu and runtime catalog differ.\n\n## Transport invariants\n\n- Streaming and non-streaming requests both receive `query.cancelSignal`.\n- Every translation calls `query.onCompletion` once.\n- Provider error events are parsed before text deltas.\n- Invalid SSE is an API error, not an empty success.\n- SSE buffering is limited to 1 MiB.\n- Non-streaming output is returned as one paragraph so Bob preserves model formatting and blank lines.\n- Validation completes on every success, error, and unexpected-response path.\n- API keys and authorization headers are never logged.\n\n`eventsource-parser` remains bundled because it correctly handles arbitrary chunk boundaries and multiline SSE without relying on browser APIs.\n\n## Performance\n\n`bun run benchmark` rebuilds the bundle, then reports absolute timings for capability resolution, adapter construction, request construction, and SSE parsing together with the current `dist/main.js` size. Each timing is the median of nine samples with 100,000 local operations.\n\nThe benchmark excludes network latency. Compare results only when the machine, Bun version, workload, and sampling method are the same; the repository does not claim a cross-version improvement without a freshly reproduced baseline.\n\n## Release safety\n\nLocal packages append a lowercase development build suffix to the repository version only inside the generated archive. Bob ignores lower, equal, and extra-component versions during installation; `<current-version>dev<build>` is newer than the matching stable version and older than the next patch release.\n\nVersion metadata and its annotated tag are pushed atomically. A new GitHub release stays unpublished until its plugin asset uploads successfully. Reruns build from the tagged source: an unfinished draft asset may be replaced, while a published release is never modified and its existing asset supplies the Appcast hash.\n\nThe Appcast is committed only after the release asset is available. If the default branch advances before that commit is pushed, the push fails without moving the tag or replacing the published asset; rerunning the workflow rebuilds the Appcast from those canonical bytes.\n\n## Comparable-project review\n\nThe review used current repository heads on 2026-07-23. No reviewed project had a complete model-capability matrix.\n\n| Project | Adopted | Rejected |\n| --- | --- | --- |\n| [CaicoLeung/bob-plugin-ollama-translator at `1b08311`](https://github.com/CaicoLeung/bob-plugin-ollama-translator/tree/1b0831155aff5ab5faaeaae3e393a9f5cb1f61cf) | Small request bodies, shared streaming transport, bundled SSE parser | Unconstrained provider/model combinations and finish-reason-only completion |\n| [kakehashi-inc/multi-ai-translator at `2385e3a`](https://github.com/kakehashi-inc/multi-ai-translator/tree/2385e3a5d7bc2f007d47f26e79f904869f5812cd) | Provider/dispatch responsibility boundary | Browser APIs, SDKs, `fetch`, and fixed cross-model generation parameters |\n| [n-AChegYag/bob-plugin-grok-translator at `7a6d8a8`](https://github.com/n-AChegYag/bob-plugin-grok-translator/tree/7a6d8a8f6222c034b866e5ffdbc9eba2455ace46) | Provider-owned native wire shapes | Undocumented `dependsOn`, scattered provider switches, universal Temperature |\n| [vitoegg/BobTranslate at `dc19ca7`](https://github.com/vitoegg/BobTranslate/tree/dc19ca7698d4d4035c527282db0348bebe5579e2) | Compact provider metadata and terminal stream handling | Separate plugin packages, unconditional reasoning/Temperature, duplicated model defaults |\n| [wuzeyou/bob-plugin-zhipu-translator at `bc6a529`](https://github.com/wuzeyou/bob-plugin-zhipu-translator/tree/bc6a529558a43d7c2696403dc13f235df0d6a08f) | Provider-specific thinking enable/disable mapping | One global rule that assumes thinking always controls Temperature |\n\n## Bob documentation coverage\n\nThe official sitemap and plugin sidebar exposed 29 `/plugin/` pages. All 29 were read on 2026-07-23.\n\n| # | Official page | Application |\n| ---: | --- | --- |\n| 1 | [Develop plugins](https://bobtranslate.com/plugin/) | JavaScriptCore runtime boundary |\n| 2 | [Create a plugin](https://bobtranslate.com/plugin/quickstart/create.html) | Required package files |\n| 3 | [Configure info.json](https://bobtranslate.com/plugin/quickstart/info.html) | Static option schema and numeric text height |\n| 4 | [Implement main.js](https://bobtranslate.com/plugin/quickstart/main.html) | Exported entry functions |\n| 5 | [Text translation](https://bobtranslate.com/plugin/quickstart/translate.html) | Query, stream, completion, cancellation, validation, timeout |\n| 6 | [OCR](https://bobtranslate.com/plugin/quickstart/ocr.html) | Reviewed; outside this translate plugin |\n| 7 | [Text to speech](https://bobtranslate.com/plugin/quickstart/tts.html) | Reviewed; outside this translate plugin |\n| 8 | [Debug plugins](https://bobtranslate.com/plugin/quickstart/debug.html) | Bob log and exported-log workflow |\n| 9 | [Package plugins](https://bobtranslate.com/plugin/quickstart/pack.html) | Flat `.bobplugin` package layout |\n| 10 | [Publish plugins](https://bobtranslate.com/plugin/quickstart/publish.html) | Appcast version, hash, URL, minimum Bob version |\n| 11 | [API introduction](https://bobtranslate.com/plugin/api/intro.html) | Available Bob globals |\n| 12 | [Modules](https://bobtranslate.com/plugin/api/module.html) | Simplified CommonJS, plugin-local modules only |\n| 13 | [Built-in modules](https://bobtranslate.com/plugin/api/builtin.html) | No assumption of Node built-ins |\n| 14 | [`$env`](https://bobtranslate.com/plugin/api/env.html) | Reviewed; no runtime need |\n| 15 | [`$info`](https://bobtranslate.com/plugin/api/info.html) | Plugin metadata boundary |\n| 16 | [`$option`](https://bobtranslate.com/plugin/api/option.html) | Flat string settings read once |\n| 17 | [`$log`](https://bobtranslate.com/plugin/api/log.html) | Secret-safe logging boundary |\n| 18 | [`$http`](https://bobtranslate.com/plugin/api/http.html) | JSON headers, stream/final handler shape, timeout, cancellation |\n| 19 | [`$websocket`](https://bobtranslate.com/plugin/api/websocket.html) | Reviewed; SSE over `$http` is sufficient |\n| 20 | [`$file`](https://bobtranslate.com/plugin/api/file.html) | Read-only plugin directory and sandbox scope |\n| 21 | [`$data`](https://bobtranslate.com/plugin/api/data.html) | Raw stream data contract |\n| 22 | [`$timer`](https://bobtranslate.com/plugin/api/timer.html) | Reviewed; no timer-based batching required |\n| 23 | [`$signal`](https://bobtranslate.com/plugin/api/signal.html) | Cancellation signal contract |\n| 24 | [Service error](https://bobtranslate.com/plugin/object/serviceerror.html) | Error type, message, addition, troubleshooting link |\n| 25 | [Translate result](https://bobtranslate.com/plugin/object/translateresult.html) | Paragraph preservation and optional Bob 1.15 reasoning display |\n| 26 | [OCR result](https://bobtranslate.com/plugin/object/ocrresult.html) | Reviewed; outside this translate plugin |\n| 27 | [TTS result](https://bobtranslate.com/plugin/object/ttsresult.html) | Reviewed; outside this translate plugin |\n| 28 | [Built-in icons](https://bobtranslate.com/plugin/addition/icon.html) | Reviewed; repository icon retained |\n| 29 | [Language codes](https://bobtranslate.com/plugin/addition/language.html) | Bob language IDs and supported-language list |\n\nThe linked [Bob 1.8 plugin changes](https://bobtranslate.com/blog/2023-05-18-180-plugin.html) were also reviewed for streaming and cancellation behavior.\n\n## Provider sources\n\n- [Azure OpenAI Responses](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses)\n- [Cloudflare AI Gateway REST API](https://developers.cloudflare.com/ai-gateway/usage/rest-api/)\n- [Gemini API selection](https://ai.google.dev/api)\n- [Gemini latest models and sampling changes](https://ai.google.dev/gemini-api/docs/generate-content/latest-model)\n- [Gemini prompting strategies](https://ai.google.dev/gemini-api/docs/prompting-strategies)\n- [Gemini thinking](https://ai.google.dev/gemini-api/docs/thinking)\n- [MiniMax China OpenAI-compatible API](https://platform.minimaxi.com/docs/api-reference/text-chat-openai)\n- [MiniMax OpenAI-compatible API](https://platform.minimax.io/docs/api-reference/text-openai-api)\n- [OpenAI model guidance](https://developers.openai.com/api/docs/guides/latest-model)\n- [OpenAI prompt engineering](https://developers.openai.com/api/docs/guides/prompt-engineering)\n- [OpenAI reasoning](https://developers.openai.com/api/docs/guides/reasoning)\n- [OpenAI Responses migration](https://developers.openai.com/api/docs/guides/migrate-to-responses)\n- [OpenRouter Quickstart](https://openrouter.ai/docs/quickstart)\n- [Vercel AI Gateway Chat Completions](https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-chat-completions/chat-completions)\n\n## Rejected complexity\n\n- Undocumented Bob option fields such as `dependsOn`\n- A user-visible provider or API-protocol selector\n- Separate API Base URL and API Path fields\n- Provider SDKs, `fetch`, browser streams, or Node.js runtime modules\n- A global Temperature override\n- A dependency-injection container or generic protocol framework\n- Multiple separately published plugins solely to obtain provider-specific settings forms\n\n## Manual Bob verification\n\nStatic checks cannot prove behavior inside the installed Bob host. Before release, install the package in Bob 1.8.0 and a current Bob version, confirm every option renders, validate one configured provider, and complete one streaming and one non-streaming translation without a runtime error.\n"},"files":{"AGENTS.md":"# Coding Agent Instructions\n\n## Bob boundary\n\nThe shipped plugin runs in Bob's JavaScriptCore host, not Node.js or a browser. Development tooling may use Node.js or browser APIs, but runtime code is limited to JavaScript built-ins, Bob globals, and bundled pure JavaScript.\n\nBob's settings form is static and space-constrained. Design it around the person configuring the plugin, not the adapter structure.\n\nBob's installed behavior is the source of truth when it disagrees with documentation, type declarations, or assumptions from other JavaScript runtimes. In particular:\n\n- Do not assume a callback-based Bob API also returns a Promise unless that behavior has been observed in Bob.\n- Preserve Bob field names that look unusual or misspelled when the runtime contract uses them.\n- Verify installation and update behavior with the copied plugin metadata, not merely the archive contents.\n\n## Product defaults\n\nUse these defaults until a concrete user need or provider contract justifies revisiting them. When evidence does not determine the user-facing behavior, present the specific tradeoff to the maintainer before changing it.\n\n- Keep the common setup to API Key, model, and an optional complete API URL. Prefer deriving provider, protocol, Base URL, and API Path internally; add another setting only when a real service cannot otherwise be configured clearly.\n- Use \"OpenAI 兼容 API\" as the user-facing category for gateways, proxies, and services exposing `/responses` or `/chat/completions`. Name individual services in the manual only when they provide a useful configuration example or behave differently.\n- Use raw model IDs as model labels by default. Add qualifiers only when they resolve a real ambiguity, not to convey provider branding, performance tiers, or marketing claims.\n- Reasoning currently offers the model default and the lowest or disabled setting. Expand it only when a demonstrated translation use case justifies the additional choice.\n- Temperature is currently omitted because supported model families do not share a stable sampling contract. Reintroduce it only with evidence for coherent behavior and a clear user benefit.\n- The system prompt changes the task, such as translation to polishing. The user prompt refines each input within that task. Keep both defaults, placeholders, and keyword insertion editable.\n- Treat saved-setting compatibility and migration as release decisions. If a change requires choosing between a clean break and a migration, confirm the intended release scope instead of inferring it from the current version.\n\n`public/info.json` is Chinese-first; common technical names may remain in English. Describe user capabilities rather than adapter mechanics, omit context Bob already displays, keep descriptions concise without trailing sentence punctuation, and link detailed guidance to the exact configuration-manual heading.\n\n## Architecture tradeoffs\n\n- Isolate provider wire differences while sharing the Bob request lifecycle. Direct adapters are preferred at the current scale; reconsider SDKs or a broader provider abstraction only when they reduce demonstrated complexity and remain compatible with JavaScriptCore.\n- Add model controls from current official provider evidence. For unknown models and partially compatible APIs, omit optional controls rather than infer support.\n- A configured non-Azure API URL currently uses an OpenAI-compatible wire format. Verified official MiniMax hosts keep the MiniMax codec because their stream semantics differ. Supporting another native-provider proxy format is a product choice, not a URL-detection shortcut.\n- Validate compatible services with a small generation request because `/models` is not a reliable cross-service contract.\n- Preserve a real SSE parser: line splitting does not handle arbitrary chunk boundaries or multiline events.\n- Evaluate performance through local selection, request construction, parsing, and bundle size. Network latency does not establish an architecture improvement.\n- Route failures through Bob's supported completion callback with a useful `ServiceError.message`. Keep diagnostic logs identifiable by the plugin identifier without logging credentials or request bodies.\n\n## Documentation boundaries\n\n- `README.md` is the concise Chinese installation and configuration entry point.\n- The Chinese and English configuration manuals own detailed user guidance.\n- `docs/architecture.md` owns rationale, source coverage, rejected alternatives, and performance evidence.\n- `.github/contributing.md` is for human contributors arriving without repository context.\n\nLink to exact manual sections instead of repeating endpoint lists or advanced settings. Keep both languages, Bob metadata, runtime defaults, and tests behaviorally aligned.\n\nSort unordered links, examples, mappings, and reference collections by their displayed label or value. Preserve task, navigation, and lifecycle order when sequence carries meaning.\n\n## Validation limits\n\nStatic checks cannot prove behavior inside Bob. Runtime changes need a packaged-plugin smoke test covering settings rendering, provider validation, one streaming translation, and one non-streaming translation.\n\nThe current Bob release ignores plugin packages whose version is not newer than the installed copy. Keep the repository version unchanged during development, and require the generated archive version to be proven newer than the installed release but older than the next stable release. Verify the copied metadata after opening the package because installation completes asynchronously.\n\nLive-provider probes are opt-in and use only credentials explicitly supplied for that run. Never discover credentials from local files or credential stores.\n","docs/architecture.md":"# Architecture\n\nLast verified: 2026-07-23.\n\n## Runtime boundary\n\nBob runs plugins in JavaScriptCore, not Node.js or a browser. Runtime code may use JavaScript built-ins, Bob APIs, and bundled pure JavaScript only. The build produces one CommonJS `main.js`; Node.js is limited to build and test scripts.\n\nThe runtime path is intentionally small:\n\n```text\n$option\n  -> parseOptions()\n  -> resolveModelControls()\n  -> provider codec\n  -> shared $http transport\n  -> Bob stream/completion callbacks\n```\n\n- `src/main.ts` is the Bob entry point.\n- `src/config.ts` parses and freezes one configuration object, derives the provider, and rejects invalid complete API URLs.\n- `src/utils/model-capabilities.ts` owns the curated model catalog and model-specific reasoning mappings.\n- `src/adapter/*.ts` owns provider URL, authentication, wire request, wire response, validation, and stream event shapes.\n- `src/adapter/base.ts` owns cancellation, network lifecycle, and exactly-once completion.\n- `src/utils/sse.ts` owns bounded SSE parsing independently of provider capability rules.\n\nAdapters never read `$option`. Provider codecs receive a validated configuration and do not know how Bob stores options.\n\n## Configuration contract\n\nBob's public option schema provides static `text` and `menu` fields. It does not expose a documented conditional-field mechanism. The plugin therefore keeps the common path short instead of exposing every internal adapter choice.\n\nThe current configuration uses these decisions:\n\n- The default OpenAI path parses and runs when Bob supplies only an API Key. Runtime defaults cover model, streaming, and reasoning.\n- Provider is derived rather than user-selected. With no API URL, the model selects the official OpenAI, Gemini, or MiniMax adapter. With an API URL, Azure hosts and paths select Azure OpenAI, verified MiniMax official hosts retain the MiniMax stream codec, and other URLs use the OpenAI-compatible adapter.\n- API URL is optional and complete. The `/responses` or `/chat/completions` suffix selects the protocol without separate Base URL, path, or protocol fields.\n- Temperature is absent from the UI and every request. Provider defaults avoid invalid parameters as model sampling contracts evolve.\n- Reasoning has two choices. Default sends no control. Disable maps to the lowest verified model-specific setting; models without a verified mapping receive no control.\n- Editable System Prompt and User Prompt defaults preserve their distinct roles: the system prompt defines purpose, while the user prompt shapes each input within that purpose. Both support `$text`, `$sourceLang`, and `$targetLang`.\n- The default system prompt starts with the translation role and explicitly prevents instruction-like source text from becoming a command. The raw source remains a separate user message.\n- Menu values are case-insensitively sorted by `value`; the `custom` model entry is the only fixed first item.\n\n## Provider contracts\n\n| Provider | Protocol | Authentication | Validation |\n| --- | --- | --- | --- |\n| Azure OpenAI | Responses or Chat Completions | `api-key` header | Minimal generation request |\n| Gemini | GenerateContent | `x-goog-api-key` header | Model listing |\n| MiniMax | Chat Completions | Bearer token | Minimal generation request |\n| OpenAI | Responses | Bearer token | `GET /v1/models` |\n| OpenAI Compatible | Responses or Chat Completions | Bearer token | Minimal generation request |\n\nProvider dispatch is an exhaustive TypeScript switch. A new wire provider requires one union member, one provider definition, one codec, a derivation rule, and contract tests. No user-facing provider menu, dependency-injection container, or secondary class hierarchy is needed.\n\n## Model controls\n\n`resolveModelControls(provider, model, mode)` is the only runtime capability resolver.\n\nDefault always omits the provider control.\n\nOnly exact model IDs with a current provider contract receive a control:\n\n| Model ID | Disable |\n| --- | --- |\n| `gemini-2.5-flash`, `gemini-2.5-flash-lite` | thinking budget `0` |\n| `gemini-2.5-pro` | thinking budget `128` |\n| `gemini-3-flash-preview`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.6-flash` | thinking level `minimal` |\n| `gemini-3-pro-preview`, `gemini-3.1-pro-preview` | thinking level `low` |\n| `gpt-5` | `minimal` |\n| `gpt-5.3-codex` | `low` |\n| `gpt-5.4-mini`, `gpt-5.6`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra` | `none` |\n| `gpt-5-pro` | `high` |\n| `MiniMax-M3` | thinking `disabled` |\n| Any other ID | omitted |\n\nRequest codecs translate the normalized result into `reasoning`, `reasoning_effort`, `thinkingConfig`, or `thinking`. Capability code does not construct transport payloads.\n\nMiniMax requests set `reasoning_split` so reasoning does not enter the translated text. Its documented cumulative stream content is converted back to deltas before Bob callbacks.\n\nMiniMax validation disables thinking and limits output for M3. It does not cap M2.x output because those models cannot disable thinking, and a short limit can end the response before translated content appears.\n\nGemini uses stateless `generateContent` and `streamGenerateContent` requests because each Bob translation is one independent generation. The Interactions API's stateful and agentic lifecycle is not needed here.\n\nTo add a curated model:\n\n1. Add its ID and provider to `MODEL_CATALOG` in sorted order.\n2. Add an exact capability entry only when current provider documentation verifies its parameter contract.\n3. Add the same menu entry to `public/info.json`.\n4. Add or update capability, provider-body, and metadata tests.\n\nThe metadata test fails if the menu and runtime catalog differ.\n\n## Transport invariants\n\n- Streaming and non-streaming requests both receive `query.cancelSignal`.\n- Every translation calls `query.onCompletion` once.\n- Provider error events are parsed before text deltas.\n- Invalid SSE is an API error, not an empty success.\n- SSE buffering is limited to 1 MiB.\n- Non-streaming output is returned as one paragraph so Bob preserves model formatting and blank lines.\n- Validation completes on every success, error, and unexpected-response path.\n- API keys and authorization headers are never logged.\n\n`eventsource-parser` remains bundled because it correctly handles arbitrary chunk boundaries and multiline SSE without relying on browser APIs.\n\n## Performance\n\n`bun run benchmark` rebuilds the bundle, then reports absolute timings for capability resolution, adapter construction, request construction, and SSE parsing together with the current `dist/main.js` size. Each timing is the median of nine samples with 100,000 local operations.\n\nThe benchmark excludes network latency. Compare results only when the machine, Bun version, workload, and sampling method are the same; the repository does not claim a cross-version improvement without a freshly reproduced baseline.\n\n## Release safety\n\nLocal packages append a lowercase development build suffix to the repository version only inside the generated archive. Bob ignores lower, equal, and extra-component versions during installation; `<current-version>dev<build>` is newer than the matching stable version and older than the next patch release.\n\nVersion metadata and its annotated tag are pushed atomically. A new GitHub release stays unpublished until its plugin asset uploads successfully. Reruns build from the tagged source: an unfinished draft asset may be replaced, while a published release is never modified and its existing asset supplies the Appcast hash.\n\nThe Appcast is committed only after the release asset is available. If the default branch advances before that commit is pushed, the push fails without moving the tag or replacing the published asset; rerunning the workflow rebuilds the Appcast from those canonical bytes.\n\n## Comparable-project review\n\nThe review used current repository heads on 2026-07-23. No reviewed project had a complete model-capability matrix.\n\n| Project | Adopted | Rejected |\n| --- | --- | --- |\n| [CaicoLeung/bob-plugin-ollama-translator at `1b08311`](https://github.com/CaicoLeung/bob-plugin-ollama-translator/tree/1b0831155aff5ab5faaeaae3e393a9f5cb1f61cf) | Small request bodies, shared streaming transport, bundled SSE parser | Unconstrained provider/model combinations and finish-reason-only completion |\n| [kakehashi-inc/multi-ai-translator at `2385e3a`](https://github.com/kakehashi-inc/multi-ai-translator/tree/2385e3a5d7bc2f007d47f26e79f904869f5812cd) | Provider/dispatch responsibility boundary | Browser APIs, SDKs, `fetch`, and fixed cross-model generation parameters |\n| [n-AChegYag/bob-plugin-grok-translator at `7a6d8a8`](https://github.com/n-AChegYag/bob-plugin-grok-translator/tree/7a6d8a8f6222c034b866e5ffdbc9eba2455ace46) | Provider-owned native wire shapes | Undocumented `dependsOn`, scattered provider switches, universal Temperature |\n| [vitoegg/BobTranslate at `dc19ca7`](https://github.com/vitoegg/BobTranslate/tree/dc19ca7698d4d4035c527282db0348bebe5579e2) | Compact provider metadata and terminal stream handling | Separate plugin packages, unconditional reasoning/Temperature, duplicated model defaults |\n| [wuzeyou/bob-plugin-zhipu-translator at `bc6a529`](https://github.com/wuzeyou/bob-plugin-zhipu-translator/tree/bc6a529558a43d7c2696403dc13f235df0d6a08f) | Provider-specific thinking enable/disable mapping | One global rule that assumes thinking always controls Temperature |\n\n## Bob documentation coverage\n\nThe official sitemap and plugin sidebar exposed 29 `/plugin/` pages. All 29 were read on 2026-07-23.\n\n| # | Official page | Application |\n| ---: | --- | --- |\n| 1 | [Develop plugins](https://bobtranslate.com/plugin/) | JavaScriptCore runtime boundary |\n| 2 | [Create a plugin](https://bobtranslate.com/plugin/quickstart/create.html) | Required package files |\n| 3 | [Configure info.json](https://bobtranslate.com/plugin/quickstart/info.html) | Static option schema and numeric text height |\n| 4 | [Implement main.js](https://bobtranslate.com/plugin/quickstart/main.html) | Exported entry functions |\n| 5 | [Text translation](https://bobtranslate.com/plugin/quickstart/translate.html) | Query, stream, completion, cancellation, validation, timeout |\n| 6 | [OCR](https://bobtranslate.com/plugin/quickstart/ocr.html) | Reviewed; outside this translate plugin |\n| 7 | [Text to speech](https://bobtranslate.com/plugin/quickstart/tts.html) | Reviewed; outside this translate plugin |\n| 8 | [Debug plugins](https://bobtranslate.com/plugin/quickstart/debug.html) | Bob log and exported-log workflow |\n| 9 | [Package plugins](https://bobtranslate.com/plugin/quickstart/pack.html) | Flat `.bobplugin` package layout |\n| 10 | [Publish plugins](https://bobtranslate.com/plugin/quickstart/publish.html) | Appcast version, hash, URL, minimum Bob version |\n| 11 | [API introduction](https://bobtranslate.com/plugin/api/intro.html) | Available Bob globals |\n| 12 | [Modules](https://bobtranslate.com/plugin/api/module.html) | Simplified CommonJS, plugin-local modules only |\n| 13 | [Built-in modules](https://bobtranslate.com/plugin/api/builtin.html) | No assumption of Node built-ins |\n| 14 | [`$env`](https://bobtranslate.com/plugin/api/env.html) | Reviewed; no runtime need |\n| 15 | [`$info`](https://bobtranslate.com/plugin/api/info.html) | Plugin metadata boundary |\n| 16 | [`$option`](https://bobtranslate.com/plugin/api/option.html) | Flat string settings read once |\n| 17 | [`$log`](https://bobtranslate.com/plugin/api/log.html) | Secret-safe logging boundary |\n| 18 | [`$http`](https://bobtranslate.com/plugin/api/http.html) | JSON headers, stream/final handler shape, timeout, cancellation |\n| 19 | [`$websocket`](https://bobtranslate.com/plugin/api/websocket.html) | Reviewed; SSE over `$http` is sufficient |\n| 20 | [`$file`](https://bobtranslate.com/plugin/api/file.html) | Read-only plugin directory and sandbox scope |\n| 21 | [`$data`](https://bobtranslate.com/plugin/api/data.html) | Raw stream data contract |\n| 22 | [`$timer`](https://bobtranslate.com/plugin/api/timer.html) | Reviewed; no timer-based batching required |\n| 23 | [`$signal`](https://bobtranslate.com/plugin/api/signal.html) | Cancellation signal contract |\n| 24 | [Service error](https://bobtranslate.com/plugin/object/serviceerror.html) | Error type, message, addition, troubleshooting link |\n| 25 | [Translate result](https://bobtranslate.com/plugin/object/translateresult.html) | Paragraph preservation and optional Bob 1.15 reasoning display |\n| 26 | [OCR result](https://bobtranslate.com/plugin/object/ocrresult.html) | Reviewed; outside this translate plugin |\n| 27 | [TTS result](https://bobtranslate.com/plugin/object/ttsresult.html) | Reviewed; outside this translate plugin |\n| 28 | [Built-in icons](https://bobtranslate.com/plugin/addition/icon.html) | Reviewed; repository icon retained |\n| 29 | [Language codes](https://bobtranslate.com/plugin/addition/language.html) | Bob language IDs and supported-language list |\n\nThe linked [Bob 1.8 plugin changes](https://bobtranslate.com/blog/2023-05-18-180-plugin.html) were also reviewed for streaming and cancellation behavior.\n\n## Provider sources\n\n- [Azure OpenAI Responses](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses)\n- [Cloudflare AI Gateway REST API](https://developers.cloudflare.com/ai-gateway/usage/rest-api/)\n- [Gemini API selection](https://ai.google.dev/api)\n- [Gemini latest models and sampling changes](https://ai.google.dev/gemini-api/docs/generate-content/latest-model)\n- [Gemini prompting strategies](https://ai.google.dev/gemini-api/docs/prompting-strategies)\n- [Gemini thinking](https://ai.google.dev/gemini-api/docs/thinking)\n- [MiniMax China OpenAI-compatible API](https://platform.minimaxi.com/docs/api-reference/text-chat-openai)\n- [MiniMax OpenAI-compatible API](https://platform.minimax.io/docs/api-reference/text-openai-api)\n- [OpenAI model guidance](https://developers.openai.com/api/docs/guides/latest-model)\n- [OpenAI prompt engineering](https://developers.openai.com/api/docs/guides/prompt-engineering)\n- [OpenAI reasoning](https://developers.openai.com/api/docs/guides/reasoning)\n- [OpenAI Responses migration](https://developers.openai.com/api/docs/guides/migrate-to-responses)\n- [OpenRouter Quickstart](https://openrouter.ai/docs/quickstart)\n- [Vercel AI Gateway Chat Completions](https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-chat-completions/chat-completions)\n\n## Rejected complexity\n\n- Undocumented Bob option fields such as `dependsOn`\n- A user-visible provider or API-protocol selector\n- Separate API Base URL and API Path fields\n- Provider SDKs, `fetch`, browser streams, or Node.js runtime modules\n- A global Temperature override\n- A dependency-injection container or generic protocol framework\n- Multiple separately published plugins solely to obtain provider-specific settings forms\n\n## Manual Bob verification\n\nStatic checks cannot prove behavior inside the installed Bob host. Before release, install the package in Bob 1.8.0 and a current Bob version, confirm every option renders, validate one configured provider, and complete one streaming and one non-streaming translation without a runtime error.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/nextai-translator/bob-plugin-openai-translator/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Coding Agent Instructions\n\n## Bob boundary\n\nThe shipped plugin runs in Bob's JavaScriptCore host, not Node.js or a browser. Development tooling may use Node.js or browser APIs, but runtime code is limited to JavaScript built-ins, Bob globals, and bundled pure JavaScript.\n\nBob's settings form is static and space-constrained. Design it around the person configuring the plugin, not the adapter structure.\n\nBob's installed behavior is the source of truth when it disagrees with documentation, type declarations, or assumptions from other JavaScript runtimes. In particular:\n\n- Do not assume a callback-based Bob API also returns a Promise unless that behavior has been observed in Bob.\n- Preserve Bob field names that look unusual or misspelled when the runtime contract uses them.\n- Verify installation and update behavior with the copied plugin metadata, not merely the archive contents.\n\n## Product defaults\n\nUse these defaults until a concrete user need or provider contract justifies revisiting them. When evidence does not determine the user-facing behavior, present the specific tradeoff to the maintainer before changing it.\n\n- Keep the common setup to API Key, model, and an optional complete API URL. Prefer deriving provider, protocol, Base URL, and API Path internally; add another setting only when a real service cannot otherwise be configured clearly.\n- Use \"OpenAI 兼容 API\" as the user-facing category for gateways, proxies, and services exposing `/responses` or `/chat/completions`. Name individual services in the manual only when they provide a useful configuration example or behave differently.\n- Use raw model IDs as model labels by default. Add qualifiers only when they resolve a real ambiguity, not to convey provider branding, performance tiers, or marketing claims.\n- Reasoning currently offers the model default and the lowest or disabled setting. Expand it only when a demonstrated translation use case justifies the additional choice.\n- Temperature is currently omitted because supported model families do not share a stable sampling contract. Reintroduce it only with evidence for coherent behavior and a clear user benefit.\n- The system prompt changes the task, such as translation to polishing. The user prompt refines each input within that task. Keep both defaults, placeholders, and keyword insertion editable.\n- Treat saved-setting compatibility and migration as release decisions. If a change requires choosing between a clean break and a migration, confirm the intended release scope instead of inferring it from the current version.\n\n`public/info.json` is Chinese-first; common technical names may remain in English. Describe user capabilities rather than adapter mechanics, omit context Bob already displays, keep descriptions concise without trailing sentence punctuation, and link detailed guidance to the exact configuration-manual heading.\n\n## Architecture tradeoffs\n\n- Isolate provider wire differences while sharing the Bob request lifecycle. Direct adapters are preferred at the current scale; reconsider SDKs or a broader provider abstraction only when they reduce demonstrated complexity and remain compatible with JavaScriptCore.\n- Add model controls from current official provider evidence. For unknown models and partially compatible APIs, omit optional controls rather than infer support.\n- A configured non-Azure API URL currently uses an OpenAI-compatible wire format. Verified official MiniMax hosts keep the MiniMax codec because their stream semantics differ. Supporting another native-provider proxy format is a product choice, not a URL-detection shortcut.\n- Validate compatible services with a small generation request because `/models` is not a reliable cross-service contract.\n- Preserve a real SSE parser: line splitting does not handle arbitrary chunk boundaries or multiline events.\n- Evaluate performance through local selection, request construction, parsing, and bundle size. Network latency does not establish an architecture improvement.\n- Route failures through Bob's supported completion callback with a useful `ServiceError.message`. Keep diagnostic logs identifiable by the plugin identifier without logging credentials or request bodies.\n\n## Documentation boundaries\n\n- `README.md` is the concise Chinese installation and configuration entry point.\n- The Chinese and English configuration manuals own detailed user guidance.\n- `docs/architecture.md` owns rationale, source coverage, rejected alternatives, and performance evidence.\n- `.github/contributing.md` is for human contributors arriving without repository context.\n\nLink to exact manual sections instead of repeating endpoint lists or advanced settings. Keep both languages, Bob metadata, runtime defaults, and tests behaviorally aligned.\n\nSort unordered links, examples, mappings, and reference collections by their displayed label or value. Preserve task, navigation, and lifecycle order when sequence carries meaning.\n\n## Validation limits\n\nStatic checks cannot prove behavior inside Bob. Runtime changes need a packaged-plugin smoke test covering settings rendering, provider validation, one streaming translation, and one non-streaming translation.\n\nThe current Bob release ignores plugin packages whose version is not newer than the installed copy. Keep the repository version unchanged during development, and require the generated archive version to be proven newer than the installed release but older than the next stable release. Verify the copied metadata after opening the package because installation completes asynchronously.\n\nLive-provider probes are opt-in and use only credentials explicitly supplied for that run. Never discover credentials from local files or credential stores.\n","isInternal":false,"tokens":1009,"sizeBytes":5738},{"name":"architecture.md","path":"docs/architecture.md","rawUrl":"https://raw.githubusercontent.com/nextai-translator/bob-plugin-openai-translator/HEAD/docs/architecture.md","title":"docs - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# Architecture\n\nLast verified: 2026-07-23.\n\n## Runtime boundary\n\nBob runs plugins in JavaScriptCore, not Node.js or a browser. Runtime code may use JavaScript built-ins, Bob APIs, and bundled pure JavaScript only. The build produces one CommonJS `main.js`; Node.js is limited to build and test scripts.\n\nThe runtime path is intentionally small:\n\n```text\n$option\n  -> parseOptions()\n  -> resolveModelControls()\n  -> provider codec\n  -> shared $http transport\n  -> Bob stream/completion callbacks\n```\n\n- `src/main.ts` is the Bob entry point.\n- `src/config.ts` parses and freezes one configuration object, derives the provider, and rejects invalid complete API URLs.\n- `src/utils/model-capabilities.ts` owns the curated model catalog and model-specific reasoning mappings.\n- `src/adapter/*.ts` owns provider URL, authentication, wire request, wire response, validation, and stream event shapes.\n- `src/adapter/base.ts` owns cancellation, network lifecycle, and exactly-once completion.\n- `src/utils/sse.ts` owns bounded SSE parsing independently of provider capability rules.\n\nAdapters never read `$option`. Provider codecs receive a validated configuration and do not know how Bob stores options.\n\n## Configuration contract\n\nBob's public option schema provides static `text` and `menu` fields. It does not expose a documented conditional-field mechanism. The plugin therefore keeps the common path short instead of exposing every internal adapter choice.\n\nThe current configuration uses these decisions:\n\n- The default OpenAI path parses and runs when Bob supplies only an API Key. Runtime defaults cover model, streaming, and reasoning.\n- Provider is derived rather than user-selected. With no API URL, the model selects the official OpenAI, Gemini, or MiniMax adapter. With an API URL, Azure hosts and paths select Azure OpenAI, verified MiniMax official hosts retain the MiniMax stream codec, and other URLs use the OpenAI-compatible adapter.\n- API URL is optional and complete. The `/responses` or `/chat/completions` suffix selects the protocol without separate Base URL, path, or protocol fields.\n- Temperature is absent from the UI and every request. Provider defaults avoid invalid parameters as model sampling contracts evolve.\n- Reasoning has two choices. Default sends no control. Disable maps to the lowest verified model-specific setting; models without a verified mapping receive no control.\n- Editable System Prompt and User Prompt defaults preserve their distinct roles: the system prompt defines purpose, while the user prompt shapes each input within that purpose. Both support `$text`, `$sourceLang`, and `$targetLang`.\n- The default system prompt starts with the translation role and explicitly prevents instruction-like source text from becoming a command. The raw source remains a separate user message.\n- Menu values are case-insensitively sorted by `value`; the `custom` model entry is the only fixed first item.\n\n## Provider contracts\n\n| Provider | Protocol | Authentication | Validation |\n| --- | --- | --- | --- |\n| Azure OpenAI | Responses or Chat Completions | `api-key` header | Minimal generation request |\n| Gemini | GenerateContent | `x-goog-api-key` header | Model listing |\n| MiniMax | Chat Completions | Bearer token | Minimal generation request |\n| OpenAI | Responses | Bearer token | `GET /v1/models` |\n| OpenAI Compatible | Responses or Chat Completions | Bearer token | Minimal generation request |\n\nProvider dispatch is an exhaustive TypeScript switch. A new wire provider requires one union member, one provider definition, one codec, a derivation rule, and contract tests. No user-facing provider menu, dependency-injection container, or secondary class hierarchy is needed.\n\n## Model controls\n\n`resolveModelControls(provider, model, mode)` is the only runtime capability resolver.\n\nDefault always omits the provider control.\n\nOnly exact model IDs with a current provider contract receive a control:\n\n| Model ID | Disable |\n| --- | --- |\n| `gemini-2.5-flash`, `gemini-2.5-flash-lite` | thinking budget `0` |\n| `gemini-2.5-pro` | thinking budget `128` |\n| `gemini-3-flash-preview`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.6-flash` | thinking level `minimal` |\n| `gemini-3-pro-preview`, `gemini-3.1-pro-preview` | thinking level `low` |\n| `gpt-5` | `minimal` |\n| `gpt-5.3-codex` | `low` |\n| `gpt-5.4-mini`, `gpt-5.6`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra` | `none` |\n| `gpt-5-pro` | `high` |\n| `MiniMax-M3` | thinking `disabled` |\n| Any other ID | omitted |\n\nRequest codecs translate the normalized result into `reasoning`, `reasoning_effort`, `thinkingConfig`, or `thinking`. Capability code does not construct transport payloads.\n\nMiniMax requests set `reasoning_split` so reasoning does not enter the translated text. Its documented cumulative stream content is converted back to deltas before Bob callbacks.\n\nMiniMax validation disables thinking and limits output for M3. It does not cap M2.x output because those models cannot disable thinking, and a short limit can end the response before translated content appears.\n\nGemini uses stateless `generateContent` and `streamGenerateContent` requests because each Bob translation is one independent generation. The Interactions API's stateful and agentic lifecycle is not needed here.\n\nTo add a curated model:\n\n1. Add its ID and provider to `MODEL_CATALOG` in sorted order.\n2. Add an exact capability entry only when current provider documentation verifies its parameter contract.\n3. Add the same menu entry to `public/info.json`.\n4. Add or update capability, provider-body, and metadata tests.\n\nThe metadata test fails if the menu and runtime catalog differ.\n\n## Transport invariants\n\n- Streaming and non-streaming requests both receive `query.cancelSignal`.\n- Every translation calls `query.onCompletion` once.\n- Provider error events are parsed before text deltas.\n- Invalid SSE is an API error, not an empty success.\n- SSE buffering is limited to 1 MiB.\n- Non-streaming output is returned as one paragraph so Bob preserves model formatting and blank lines.\n- Validation completes on every success, error, and unexpected-response path.\n- API keys and authorization headers are never logged.\n\n`eventsource-parser` remains bundled because it correctly handles arbitrary chunk boundaries and multiline SSE without relying on browser APIs.\n\n## Performance\n\n`bun run benchmark` rebuilds the bundle, then reports absolute timings for capability resolution, adapter construction, request construction, and SSE parsing together with the current `dist/main.js` size. Each timing is the median of nine samples with 100,000 local operations.\n\nThe benchmark excludes network latency. Compare results only when the machine, Bun version, workload, and sampling method are the same; the repository does not claim a cross-version improvement without a freshly reproduced baseline.\n\n## Release safety\n\nLocal packages append a lowercase development build suffix to the repository version only inside the generated archive. Bob ignores lower, equal, and extra-component versions during installation; `<current-version>dev<build>` is newer than the matching stable version and older than the next patch release.\n\nVersion metadata and its annotated tag are pushed atomically. A new GitHub release stays unpublished until its plugin asset uploads successfully. Reruns build from the tagged source: an unfinished draft asset may be replaced, while a published release is never modified and its existing asset supplies the Appcast hash.\n\nThe Appcast is committed only after the release asset is available. If the default branch advances before that commit is pushed, the push fails without moving the tag or replacing the published asset; rerunning the workflow rebuilds the Appcast from those canonical bytes.\n\n## Comparable-project review\n\nThe review used current repository heads on 2026-07-23. No reviewed project had a complete model-capability matrix.\n\n| Project | Adopted | Rejected |\n| --- | --- | --- |\n| [CaicoLeung/bob-plugin-ollama-translator at `1b08311`](https://github.com/CaicoLeung/bob-plugin-ollama-translator/tree/1b0831155aff5ab5faaeaae3e393a9f5cb1f61cf) | Small request bodies, shared streaming transport, bundled SSE parser | Unconstrained provider/model combinations and finish-reason-only completion |\n| [kakehashi-inc/multi-ai-translator at `2385e3a`](https://github.com/kakehashi-inc/multi-ai-translator/tree/2385e3a5d7bc2f007d47f26e79f904869f5812cd) | Provider/dispatch responsibility boundary | Browser APIs, SDKs, `fetch`, and fixed cross-model generation parameters |\n| [n-AChegYag/bob-plugin-grok-translator at `7a6d8a8`](https://github.com/n-AChegYag/bob-plugin-grok-translator/tree/7a6d8a8f6222c034b866e5ffdbc9eba2455ace46) | Provider-owned native wire shapes | Undocumented `dependsOn`, scattered provider switches, universal Temperature |\n| [vitoegg/BobTranslate at `dc19ca7`](https://github.com/vitoegg/BobTranslate/tree/dc19ca7698d4d4035c527282db0348bebe5579e2) | Compact provider metadata and terminal stream handling | Separate plugin packages, unconditional reasoning/Temperature, duplicated model defaults |\n| [wuzeyou/bob-plugin-zhipu-translator at `bc6a529`](https://github.com/wuzeyou/bob-plugin-zhipu-translator/tree/bc6a529558a43d7c2696403dc13f235df0d6a08f) | Provider-specific thinking enable/disable mapping | One global rule that assumes thinking always controls Temperature |\n\n## Bob documentation coverage\n\nThe official sitemap and plugin sidebar exposed 29 `/plugin/` pages. All 29 were read on 2026-07-23.\n\n| # | Official page | Application |\n| ---: | --- | --- |\n| 1 | [Develop plugins](https://bobtranslate.com/plugin/) | JavaScriptCore runtime boundary |\n| 2 | [Create a plugin](https://bobtranslate.com/plugin/quickstart/create.html) | Required package files |\n| 3 | [Configure info.json](https://bobtranslate.com/plugin/quickstart/info.html) | Static option schema and numeric text height |\n| 4 | [Implement main.js](https://bobtranslate.com/plugin/quickstart/main.html) | Exported entry functions |\n| 5 | [Text translation](https://bobtranslate.com/plugin/quickstart/translate.html) | Query, stream, completion, cancellation, validation, timeout |\n| 6 | [OCR](https://bobtranslate.com/plugin/quickstart/ocr.html) | Reviewed; outside this translate plugin |\n| 7 | [Text to speech](https://bobtranslate.com/plugin/quickstart/tts.html) | Reviewed; outside this translate plugin |\n| 8 | [Debug plugins](https://bobtranslate.com/plugin/quickstart/debug.html) | Bob log and exported-log workflow |\n| 9 | [Package plugins](https://bobtranslate.com/plugin/quickstart/pack.html) | Flat `.bobplugin` package layout |\n| 10 | [Publish plugins](https://bobtranslate.com/plugin/quickstart/publish.html) | Appcast version, hash, URL, minimum Bob version |\n| 11 | [API introduction](https://bobtranslate.com/plugin/api/intro.html) | Available Bob globals |\n| 12 | [Modules](https://bobtranslate.com/plugin/api/module.html) | Simplified CommonJS, plugin-local modules only |\n| 13 | [Built-in modules](https://bobtranslate.com/plugin/api/builtin.html) | No assumption of Node built-ins |\n| 14 | [`$env`](https://bobtranslate.com/plugin/api/env.html) | Reviewed; no runtime need |\n| 15 | [`$info`](https://bobtranslate.com/plugin/api/info.html) | Plugin metadata boundary |\n| 16 | [`$option`](https://bobtranslate.com/plugin/api/option.html) | Flat string settings read once |\n| 17 | [`$log`](https://bobtranslate.com/plugin/api/log.html) | Secret-safe logging boundary |\n| 18 | [`$http`](https://bobtranslate.com/plugin/api/http.html) | JSON headers, stream/final handler shape, timeout, cancellation |\n| 19 | [`$websocket`](https://bobtranslate.com/plugin/api/websocket.html) | Reviewed; SSE over `$http` is sufficient |\n| 20 | [`$file`](https://bobtranslate.com/plugin/api/file.html) | Read-only plugin directory and sandbox scope |\n| 21 | [`$data`](https://bobtranslate.com/plugin/api/data.html) | Raw stream data contract |\n| 22 | [`$timer`](https://bobtranslate.com/plugin/api/timer.html) | Reviewed; no timer-based batching required |\n| 23 | [`$signal`](https://bobtranslate.com/plugin/api/signal.html) | Cancellation signal contract |\n| 24 | [Service error](https://bobtranslate.com/plugin/object/serviceerror.html) | Error type, message, addition, troubleshooting link |\n| 25 | [Translate result](https://bobtranslate.com/plugin/object/translateresult.html) | Paragraph preservation and optional Bob 1.15 reasoning display |\n| 26 | [OCR result](https://bobtranslate.com/plugin/object/ocrresult.html) | Reviewed; outside this translate plugin |\n| 27 | [TTS result](https://bobtranslate.com/plugin/object/ttsresult.html) | Reviewed; outside this translate plugin |\n| 28 | [Built-in icons](https://bobtranslate.com/plugin/addition/icon.html) | Reviewed; repository icon retained |\n| 29 | [Language codes](https://bobtranslate.com/plugin/addition/language.html) | Bob language IDs and supported-language list |\n\nThe linked [Bob 1.8 plugin changes](https://bobtranslate.com/blog/2023-05-18-180-plugin.html) were also reviewed for streaming and cancellation behavior.\n\n## Provider sources\n\n- [Azure OpenAI Responses](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses)\n- [Cloudflare AI Gateway REST API](https://developers.cloudflare.com/ai-gateway/usage/rest-api/)\n- [Gemini API selection](https://ai.google.dev/api)\n- [Gemini latest models and sampling changes](https://ai.google.dev/gemini-api/docs/generate-content/latest-model)\n- [Gemini prompting strategies](https://ai.google.dev/gemini-api/docs/prompting-strategies)\n- [Gemini thinking](https://ai.google.dev/gemini-api/docs/thinking)\n- [MiniMax China OpenAI-compatible API](https://platform.minimaxi.com/docs/api-reference/text-chat-openai)\n- [MiniMax OpenAI-compatible API](https://platform.minimax.io/docs/api-reference/text-openai-api)\n- [OpenAI model guidance](https://developers.openai.com/api/docs/guides/latest-model)\n- [OpenAI prompt engineering](https://developers.openai.com/api/docs/guides/prompt-engineering)\n- [OpenAI reasoning](https://developers.openai.com/api/docs/guides/reasoning)\n- [OpenAI Responses migration](https://developers.openai.com/api/docs/guides/migrate-to-responses)\n- [OpenRouter Quickstart](https://openrouter.ai/docs/quickstart)\n- [Vercel AI Gateway Chat Completions](https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-chat-completions/chat-completions)\n\n## Rejected complexity\n\n- Undocumented Bob option fields such as `dependsOn`\n- A user-visible provider or API-protocol selector\n- Separate API Base URL and API Path fields\n- Provider SDKs, `fetch`, browser streams, or Node.js runtime modules\n- A global Temperature override\n- A dependency-injection container or generic protocol framework\n- Multiple separately published plugins solely to obtain provider-specific settings forms\n\n## Manual Bob verification\n\nStatic checks cannot prove behavior inside the installed Bob host. Before release, install the package in Bob 1.8.0 and a current Bob version, confirm every option renders, validate one configured provider, and complete one streaming and one non-streaming translation without a runtime error.\n","isInternal":false,"tokens":3503,"sizeBytes":15161}],"systemPromptSnippet":"<yakaai_skills repo=\"nextai-translator/bob-plugin-openai-translator\">\n<!-- File: AGENTS.md (Tokens: ~1009 | Category: root-instruction) -->\n# Coding Agent Instructions\n\n## Bob boundary\n\nThe shipped plugin runs in Bob's JavaScriptCore host, not Node.js or a browser. Development tooling may use Node.js or browser APIs, but runtime code is limited to JavaScript built-ins, Bob globals, and bundled pure JavaScript.\n\nBob's settings form is static and space-constrained. Design it around the person configuring the plugin, not the adapter structure.\n\nBob's installed behavior is the source of truth when it disagrees with documentation, type declarations, or assumptions from other JavaScript runtimes. In particular:\n\n- Do not assume a callback-based Bob API also returns a Promise unless that behavior has been observed in Bob.\n- Preserve Bob field names that look unusual or misspelled when the runtime contract uses them.\n- Verify installation and update behavior with the copied plugin metadata, not merely the archive contents.\n\n## Product defaults\n\nUse these defaults until a concrete user need or provider contract justifies revisiting them. When evidence does not determine the user-facing behavior, present the specific tradeoff to the maintainer before changing it.\n\n- Keep the common setup to API Key, model, and an optional complete API URL. Prefer deriving provider, protocol, Base URL, and API Path internally; add another setting only when a real service cannot otherwise be configured clearly.\n- Use \"OpenAI 兼容 API\" as the user-facing category for gateways, proxies, and services exposing `/responses` or `/chat/completions`. Name individual services in the manual only when they provide a useful configuration example or behave differently.\n- Use raw model IDs as model labels by default. Add qualifiers only when they resolve a real ambiguity, not to convey provider branding, performance tiers, or marketing claims.\n- Reasoning currently offers the model default and the lowest or disabled setting. Expand it only when a demonstrated translation use case justifies the additional choice.\n- Temperature is currently omitted because supported model families do not share a stable sampling contract. Reintroduce it only with evidence for coherent behavior and a clear user benefit.\n- The system prompt changes the task, such as translation to polishing. The user prompt refines each input within that task. Keep both defaults, placeholders, and keyword insertion editable.\n- Treat saved-setting compatibility and migration as release decisions. If a change requires choosing between a clean break and a migration, confirm the intended release scope instead of inferring it from the current version.\n\n`public/info.json` is Chinese-first; common technical names may remain in English. Describe user capabilities rather than adapter mechanics, omit context Bob already displays, keep descriptions concise without trailing sentence punctuation, and link detailed guidance to the exact configuration-manual heading.\n\n## Architecture tradeoffs\n\n- Isolate provider wire differences while sharing the Bob request lifecycle. Direct adapters are preferred at the current scale; reconsider SDKs or a broader provider abstraction only when they reduce demonstrated complexity and remain compatible with JavaScriptCore.\n- Add model controls from current official provider evidence. For unknown models and partially compatible APIs, omit optional controls rather than infer support.\n- A configured non-Azure API URL currently uses an OpenAI-compatible wire format. Verified official MiniMax hosts keep the MiniMax codec because their stream semantics differ. Supporting another native-provider proxy format is a product choice, not a URL-detection shortcut.\n- Validate compatible services with a small generation request because `/models` is not a reliable cross-service contract.\n- Preserve a real SSE parser: line splitting does not handle arbitrary chunk boundaries or multiline events.\n- Evaluate performance through local selection, request construction, parsing, and bundle size. Network latency does not establish an architecture improvement.\n- Route failures through Bob's supported completion callback with a useful `ServiceError.message`. Keep diagnostic logs identifiable by the plugin identifier without logging credentials or request bodies.\n\n## Documentation boundaries\n\n- `README.md` is the concise Chinese installation and configuration entry point.\n- The Chinese and English configuration manuals own detailed user guidance.\n- `docs/architecture.md` owns rationale, source coverage, rejected alternatives, and performance evidence.\n- `.github/contributing.md` is for human contributors arriving without repository context.\n\nLink to exact manual sections instead of repeating endpoint lists or advanced settings. Keep both languages, Bob metadata, runtime defaults, and tests behaviorally aligned.\n\nSort unordered links, examples, mappings, and reference collections by their displayed label or value. Preserve task, navigation, and lifecycle order when sequence carries meaning.\n\n## Validation limits\n\nStatic checks cannot prove behavior inside Bob. Runtime changes need a packaged-plugin smoke test covering settings rendering, provider validation, one streaming translation, and one non-streaming translation.\n\nThe current Bob release ignores plugin packages whose version is not newer than the installed copy. Keep the repository version unchanged during development, and require the generated archive version to be proven newer than the installed release but older than the next stable release. Verify the copied metadata after opening the package because installation completes asynchronously.\n\nLive-provider probes are opt-in and use only credentials explicitly supplied for that run. Never discover credentials from local files or credential stores.\n\n<!-- File: docs/architecture.md (Tokens: ~3503 | Category: project-spec) -->\n# Architecture\n\nLast verified: 2026-07-23.\n\n## Runtime boundary\n\nBob runs plugins in JavaScriptCore, not Node.js or a browser. Runtime code may use JavaScript built-ins, Bob APIs, and bundled pure JavaScript only. The build produces one CommonJS `main.js`; Node.js is limited to build and test scripts.\n\nThe runtime path is intentionally small:\n\n```text\n$option\n  -> parseOptions()\n  -> resolveModelControls()\n  -> provider codec\n  -> shared $http transport\n  -> Bob stream/completion callbacks\n```\n\n- `src/main.ts` is the Bob entry point.\n- `src/config.ts` parses and freezes one configuration object, derives the provider, and rejects invalid complete API URLs.\n- `src/utils/model-capabilities.ts` owns the curated model catalog and model-specific reasoning mappings.\n- `src/adapter/*.ts` owns provider URL, authentication, wire request, wire response, validation, and stream event shapes.\n- `src/adapter/base.ts` owns cancellation, network lifecycle, and exactly-once completion.\n- `src/utils/sse.ts` owns bounded SSE parsing independently of provider capability rules.\n\nAdapters never read `$option`. Provider codecs receive a validated configuration and do not know how Bob stores options.\n\n## Configuration contract\n\nBob's public option schema provides static `text` and `menu` fields. It does not expose a documented conditional-field mechanism. The plugin therefore keeps the common path short instead of exposing every internal adapter choice.\n\nThe current configuration uses these decisions:\n\n- The default OpenAI path parses and runs when Bob supplies only an API Key. Runtime defaults cover model, streaming, and reasoning.\n- Provider is derived rather than user-selected. With no API URL, the model selects the official OpenAI, Gemini, or MiniMax adapter. With an API URL, Azure hosts and paths select Azure OpenAI, verified MiniMax official hosts retain the MiniMax stream codec, and other URLs use the OpenAI-compatible adapter.\n- API URL is optional and complete. The `/responses` or `/chat/completions` suffix selects the protocol without separate Base URL, path, or protocol fields.\n- Temperature is absent from the UI and every request. Provider defaults avoid invalid parameters as model sampling contracts evolve.\n- Reasoning has two choices. Default sends no control. Disable maps to the lowest verified model-specific setting; models without a verified mapping receive no control.\n- Editable System Prompt and User Prompt defaults preserve their distinct roles: the system prompt defines purpose, while the user prompt shapes each input within that purpose. Both support `$text`, `$sourceLang`, and `$targetLang`.\n- The default system prompt starts with the translation role and explicitly prevents instruction-like source text from becoming a command. The raw source remains a separate user message.\n- Menu values are case-insensitively sorted by `value`; the `custom` model entry is the only fixed first item.\n\n## Provider contracts\n\n| Provider | Protocol | Authentication | Validation |\n| --- | --- | --- | --- |\n| Azure OpenAI | Responses or Chat Completions | `api-key` header | Minimal generation request |\n| Gemini | GenerateContent | `x-goog-api-key` header | Model listing |\n| MiniMax | Chat Completions | Bearer token | Minimal generation request |\n| OpenAI | Responses | Bearer token | `GET /v1/models` |\n| OpenAI Compatible | Responses or Chat Completions | Bearer token | Minimal generation request |\n\nProvider dispatch is an exhaustive TypeScript switch. A new wire provider requires one union member, one provider definition, one codec, a derivation rule, and contract tests. No user-facing provider menu, dependency-injection container, or secondary class hierarchy is needed.\n\n## Model controls\n\n`resolveModelControls(provider, model, mode)` is the only runtime capability resolver.\n\nDefault always omits the provider control.\n\nOnly exact model IDs with a current provider contract receive a control:\n\n| Model ID | Disable |\n| --- | --- |\n| `gemini-2.5-flash`, `gemini-2.5-flash-lite` | thinking budget `0` |\n| `gemini-2.5-pro` | thinking budget `128` |\n| `gemini-3-flash-preview`, `gemini-3.5-flash`, `gemini-3.5-flash-lite`, `gemini-3.6-flash` | thinking level `minimal` |\n| `gemini-3-pro-preview`, `gemini-3.1-pro-preview` | thinking level `low` |\n| `gpt-5` | `minimal` |\n| `gpt-5.3-codex` | `low` |\n| `gpt-5.4-mini`, `gpt-5.6`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra` | `none` |\n| `gpt-5-pro` | `high` |\n| `MiniMax-M3` | thinking `disabled` |\n| Any other ID | omitted |\n\nRequest codecs translate the normalized result into `reasoning`, `reasoning_effort`, `thinkingConfig`, or `thinking`. Capability code does not construct transport payloads.\n\nMiniMax requests set `reasoning_split` so reasoning does not enter the translated text. Its documented cumulative stream content is converted back to deltas before Bob callbacks.\n\nMiniMax validation disables thinking and limits output for M3. It does not cap M2.x output because those models cannot disable thinking, and a short limit can end the response before translated content appears.\n\nGemini uses stateless `generateContent` and `streamGenerateContent` requests because each Bob translation is one independent generation. The Interactions API's stateful and agentic lifecycle is not needed here.\n\nTo add a curated model:\n\n1. Add its ID and provider to `MODEL_CATALOG` in sorted order.\n2. Add an exact capability entry only when current provider documentation verifies its parameter contract.\n3. Add the same menu entry to `public/info.json`.\n4. Add or update capability, provider-body, and metadata tests.\n\nThe metadata test fails if the menu and runtime catalog differ.\n\n## Transport invariants\n\n- Streaming and non-streaming requests both receive `query.cancelSignal`.\n- Every translation calls `query.onCompletion` once.\n- Provider error events are parsed before text deltas.\n- Invalid SSE is an API error, not an empty success.\n- SSE buffering is limited to 1 MiB.\n- Non-streaming output is returned as one paragraph so Bob preserves model formatting and blank lines.\n- Validation completes on every success, error, and unexpected-response path.\n- API keys and authorization headers are never logged.\n\n`eventsource-parser` remains bundled because it correctly handles arbitrary chunk boundaries and multiline SSE without relying on browser APIs.\n\n## Performance\n\n`bun run benchmark` rebuilds the bundle, then reports absolute timings for capability resolution, adapter construction, request construction, and SSE parsing together with the current `dist/main.js` size. Each timing is the median of nine samples with 100,000 local operations.\n\nThe benchmark excludes network latency. Compare results only when the machine, Bun version, workload, and sampling method are the same; the repository does not claim a cross-version improvement without a freshly reproduced baseline.\n\n## Release safety\n\nLocal packages append a lowercase development build suffix to the repository version only inside the generated archive. Bob ignores lower, equal, and extra-component versions during installation; `<current-version>dev<build>` is newer than the matching stable version and older than the next patch release.\n\nVersion metadata and its annotated tag are pushed atomically. A new GitHub release stays unpublished until its plugin asset uploads successfully. Reruns build from the tagged source: an unfinished draft asset may be replaced, while a published release is never modified and its existing asset supplies the Appcast hash.\n\nThe Appcast is committed only after the release asset is available. If the default branch advances before that commit is pushed, the push fails without moving the tag or replacing the published asset; rerunning the workflow rebuilds the Appcast from those canonical bytes.\n\n## Comparable-project review\n\nThe review used current repository heads on 2026-07-23. No reviewed project had a complete model-capability matrix.\n\n| Project | Adopted | Rejected |\n| --- | --- | --- |\n| [CaicoLeung/bob-plugin-ollama-translator at `1b08311`](https://github.com/CaicoLeung/bob-plugin-ollama-translator/tree/1b0831155aff5ab5faaeaae3e393a9f5cb1f61cf) | Small request bodies, shared streaming transport, bundled SSE parser | Unconstrained provider/model combinations and finish-reason-only completion |\n| [kakehashi-inc/multi-ai-translator at `2385e3a`](https://github.com/kakehashi-inc/multi-ai-translator/tree/2385e3a5d7bc2f007d47f26e79f904869f5812cd) | Provider/dispatch responsibility boundary | Browser APIs, SDKs, `fetch`, and fixed cross-model generation parameters |\n| [n-AChegYag/bob-plugin-grok-translator at `7a6d8a8`](https://github.com/n-AChegYag/bob-plugin-grok-translator/tree/7a6d8a8f6222c034b866e5ffdbc9eba2455ace46) | Provider-owned native wire shapes | Undocumented `dependsOn`, scattered provider switches, universal Temperature |\n| [vitoegg/BobTranslate at `dc19ca7`](https://github.com/vitoegg/BobTranslate/tree/dc19ca7698d4d4035c527282db0348bebe5579e2) | Compact provider metadata and terminal stream handling | Separate plugin packages, unconditional reasoning/Temperature, duplicated model defaults |\n| [wuzeyou/bob-plugin-zhipu-translator at `bc6a529`](https://github.com/wuzeyou/bob-plugin-zhipu-translator/tree/bc6a529558a43d7c2696403dc13f235df0d6a08f) | Provider-specific thinking enable/disable mapping | One global rule that assumes thinking always controls Temperature |\n\n## Bob documentation coverage\n\nThe official sitemap and plugin sidebar exposed 29 `/plugin/` pages. All 29 were read on 2026-07-23.\n\n| # | Official page | Application |\n| ---: | --- | --- |\n| 1 | [Develop plugins](https://bobtranslate.com/plugin/) | JavaScriptCore runtime boundary |\n| 2 | [Create a plugin](https://bobtranslate.com/plugin/quickstart/create.html) | Required package files |\n| 3 | [Configure info.json](https://bobtranslate.com/plugin/quickstart/info.html) | Static option schema and numeric text height |\n| 4 | [Implement main.js](https://bobtranslate.com/plugin/quickstart/main.html) | Exported entry functions |\n| 5 | [Text translation](https://bobtranslate.com/plugin/quickstart/translate.html) | Query, stream, completion, cancellation, validation, timeout |\n| 6 | [OCR](https://bobtranslate.com/plugin/quickstart/ocr.html) | Reviewed; outside this translate plugin |\n| 7 | [Text to speech](https://bobtranslate.com/plugin/quickstart/tts.html) | Reviewed; outside this translate plugin |\n| 8 | [Debug plugins](https://bobtranslate.com/plugin/quickstart/debug.html) | Bob log and exported-log workflow |\n| 9 | [Package plugins](https://bobtranslate.com/plugin/quickstart/pack.html) | Flat `.bobplugin` package layout |\n| 10 | [Publish plugins](https://bobtranslate.com/plugin/quickstart/publish.html) | Appcast version, hash, URL, minimum Bob version |\n| 11 | [API introduction](https://bobtranslate.com/plugin/api/intro.html) | Available Bob globals |\n| 12 | [Modules](https://bobtranslate.com/plugin/api/module.html) | Simplified CommonJS, plugin-local modules only |\n| 13 | [Built-in modules](https://bobtranslate.com/plugin/api/builtin.html) | No assumption of Node built-ins |\n| 14 | [`$env`](https://bobtranslate.com/plugin/api/env.html) | Reviewed; no runtime need |\n| 15 | [`$info`](https://bobtranslate.com/plugin/api/info.html) | Plugin metadata boundary |\n| 16 | [`$option`](https://bobtranslate.com/plugin/api/option.html) | Flat string settings read once |\n| 17 | [`$log`](https://bobtranslate.com/plugin/api/log.html) | Secret-safe logging boundary |\n| 18 | [`$http`](https://bobtranslate.com/plugin/api/http.html) | JSON headers, stream/final handler shape, timeout, cancellation |\n| 19 | [`$websocket`](https://bobtranslate.com/plugin/api/websocket.html) | Reviewed; SSE over `$http` is sufficient |\n| 20 | [`$file`](https://bobtranslate.com/plugin/api/file.html) | Read-only plugin directory and sandbox scope |\n| 21 | [`$data`](https://bobtranslate.com/plugin/api/data.html) | Raw stream data contract |\n| 22 | [`$timer`](https://bobtranslate.com/plugin/api/timer.html) | Reviewed; no timer-based batching required |\n| 23 | [`$signal`](https://bobtranslate.com/plugin/api/signal.html) | Cancellation signal contract |\n| 24 | [Service error](https://bobtranslate.com/plugin/object/serviceerror.html) | Error type, message, addition, troubleshooting link |\n| 25 | [Translate result](https://bobtranslate.com/plugin/object/translateresult.html) | Paragraph preservation and optional Bob 1.15 reasoning display |\n| 26 | [OCR result](https://bobtranslate.com/plugin/object/ocrresult.html) | Reviewed; outside this translate plugin |\n| 27 | [TTS result](https://bobtranslate.com/plugin/object/ttsresult.html) | Reviewed; outside this translate plugin |\n| 28 | [Built-in icons](https://bobtranslate.com/plugin/addition/icon.html) | Reviewed; repository icon retained |\n| 29 | [Language codes](https://bobtranslate.com/plugin/addition/language.html) | Bob language IDs and supported-language list |\n\nThe linked [Bob 1.8 plugin changes](https://bobtranslate.com/blog/2023-05-18-180-plugin.html) were also reviewed for streaming and cancellation behavior.\n\n## Provider sources\n\n- [Azure OpenAI Responses](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses)\n- [Cloudflare AI Gateway REST API](https://developers.cloudflare.com/ai-gateway/usage/rest-api/)\n- [Gemini API selection](https://ai.google.dev/api)\n- [Gemini latest models and sampling changes](https://ai.google.dev/gemini-api/docs/generate-content/latest-model)\n- [Gemini prompting strategies](https://ai.google.dev/gemini-api/docs/prompting-strategies)\n- [Gemini thinking](https://ai.google.dev/gemini-api/docs/thinking)\n- [MiniMax China OpenAI-compatible API](https://platform.minimaxi.com/docs/api-reference/text-chat-openai)\n- [MiniMax OpenAI-compatible API](https://platform.minimax.io/docs/api-reference/text-openai-api)\n- [OpenAI model guidance](https://developers.openai.com/api/docs/guides/latest-model)\n- [OpenAI prompt engineering](https://developers.openai.com/api/docs/guides/prompt-engineering)\n- [OpenAI reasoning](https://developers.openai.com/api/docs/guides/reasoning)\n- [OpenAI Responses migration](https://developers.openai.com/api/docs/guides/migrate-to-responses)\n- [OpenRouter Quickstart](https://openrouter.ai/docs/quickstart)\n- [Vercel AI Gateway Chat Completions](https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-chat-completions/chat-completions)\n\n## Rejected complexity\n\n- Undocumented Bob option fields such as `dependsOn`\n- A user-visible provider or API-protocol selector\n- Separate API Base URL and API Path fields\n- Provider SDKs, `fetch`, browser streams, or Node.js runtime modules\n- A global Temperature override\n- A dependency-injection container or generic protocol framework\n- Multiple separately published plugins solely to obtain provider-specific settings forms\n\n## Manual Bob verification\n\nStatic checks cannot prove behavior inside the installed Bob host. Before release, install the package in Bob 1.8.0 and a current Bob version, confirm every option renders, validate one configured provider, and complete one streaming and one non-streaming translation without a runtime error.\n</yakaai_skills>"}