Files
OmniRoute/docs/i18n/km/docs/security/GUARDRAILS.md
Diego Rodrigues de Sa e Souza 8feea123bb feat(docs): mirror every docs/ page in all 65 locales (#14106)
* feat(docs): mirror every docs/ page in all 65 locales

Extends the documentation mirrors from the 22-page core set (#13940) to
every Markdown page under docs/: 152 sources x 65 locales = 9,880 mirrors
(6,208 new), language bars rewritten for the full locale list, state
adopted so the blocking drift gate now covers all 152 pages.

run-translation.mjs: an oversized block made only of table rows or list
items (PROVIDER_REFERENCE.md 244-row table, FREE_TIERS.md 71-item list) is
cut at item boundaries and rejoined without a blank line — the single
16-40 KB request outlived the backend socket for verbose scripts. 48
older mirrors whose tables had lost rows were retranslated with --force.

* docs(i18n): refresh mirrors for the sources the base changed since the branch cut

Section-level retranslation of the 29 docs (and README.md) whose source
or mirrors moved on release/v3.8.51 during the run, then state adoption;
the drift gate is green again on the merged tree.
2026-09-18 13:16:46 -03:00

120 KiB
Raw Blame History

Guardrails (ខ្មែរ)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


ប្រភពយោងផ្លូវការ: src/lib/guardrails/ បានធ្វើបច្ចុប្បន្នភាពចុងក្រោយ: 2026-08-29 — v3.8.51 (ប្រភពដើមនៃប្រតិចារឹក Video Bridge ត្រូវបានប្រកាសដោយអ្នកហៅ ហើយមិនទាន់ត្រូវបានផ្ទៀងផ្ទាត់ដោយម៉ាស៊ីនបម្រើនៅឡើយ — បានបញ្ជាក់ឱ្យច្បាស់តាម #11661)

Guardrails អនុវត្តសុវត្ថិភាព គោលការណ៍ និងការបំប្លែងខ្លឹមសារ នៅចំណុចប្រទាក់ រវាង OmniRoute និងអ្នកផ្តល់សេវាខាងដើម។ Guardrail នីមួយៗអាចត្រួតពិនិត្យ (និង ជាជម្រើស អាចបដិសេធ បំប្លែង ឬបន្ថែមចំណារពន្យល់ទៅលើ) payload សំណើ (preCall) និង ការឆ្លើយតបពីខាងដើម (postCall)។

ប្រព័ន្ធនេះមានលក្ខណៈ fail-open៖ ប្រសិនបើ guardrail មួយបោះ exception ខណៈពេលប្រតិបត្តិការ registry នឹងកត់ត្រាកំហុស ហើយបន្តទៅ guardrail បន្ទាប់ ជំនួសឱ្យការធ្វើឱ្យសំណើ បរាជ័យ។ ការទប់ស្កាត់គឺជាការសម្រេចចិត្តជាក់លាក់ (block: true) មិនមែនកើតឡើងដោយចៃដន្យឡើយ។

Guardrail ដែលភ្ជាប់មកជាមួយ

registry ផ្ទុក guardrail ចំនួនប្រាំមួយដោយស្វ័យប្រវត្តិតាមលំដាប់អាទិភាព នៅពេល import (សូមមើល registry.tsregisterDefaultGuardrails()):

អាទិភាព ឈ្មោះ ដំណាក់កាល ឯកសារ
5 vision-bridge preCall visionBridge.ts
6 audio-bridge preCall audioBridge.ts
7 video-bridge preCall videoBridge.ts
10 pii-masker pre + post piiMasker.ts
20 prompt-injection preCall promptInjection.ts
95 credential-masker pre + post credentialMasker.ts

លេខអាទិភាពទាបជាង ដំណើរការ មុន

Vision Bridge (visionBridge.ts) — Modality Bridge PR-1

ស្ទាក់ចាប់សំណើដែលមានរូបភាព និងមានគោលដៅទៅកាន់ ម៉ូដែលដែលមិនគាំទ្រចក្ខុវិស័យ ហើយ បញ្ជូនសំណើទាំងមូលឡើងវិញទៅម៉ូដែលដែលមានសមត្ថភាពចក្ខុវិស័យ ឬជំនួសផ្នែករូបភាព ដោយការពិពណ៌នាជាអត្ថបទ ដែលបង្កើតដោយម៉ូដែលចក្ខុវិស័យដែលអាចកំណត់រចនាសម្ព័ន្ធបាន មុនពេល ការហៅទៅខាងដើម។ វាអនុញ្ញាតឱ្យអ្នកផ្តល់សេវាដែលគាំទ្រតែអត្ថបទ អាចដោះស្រាយ payload ពហុមធ្យោបាយដោយតម្លាភាព។

លំហូរ៖

  1. រំលង ប្រសិនបើម៉ូដែលគោលដៅគាំទ្រចក្ខុវិស័យរួចហើយ (លុះត្រាតែវាមាននៅក្នុង បញ្ជីបង្ខំឱ្យឆ្លងកាត់ bridge isVisionBridgeForcedModel)។
  2. ស្រង់ផ្នែករូបភាពតាមរយៈ extractImageParts(messages) (visionBridgeHelpers.ts) ដែលផ្ទេរភារកិច្ចទៅ ឧបករណ៍រកឃើញមេឌៀរួម detectMediaParts() នៅក្នុង open-sse/utils/mediaParts.ts — ជា ប្រភពយោងផ្លូវការតែមួយ ដែលប្រើរួមជាមួយតម្រងភាពឆបគ្នាបែប combo។ ការស្រង់ត្រូវបានកំណត់ដោយបញ្ជីអនុញ្ញាត ចំពោះតែផ្នែកកម្រិតកំពូលដែលមានទម្រង់ ដែល replaceImageParts អាចភ្ជាប់ត្រឡប់ចូលវិញបាន (កិច្ចសន្យា extract↔replace)៖ OpenAI image_url, Anthropic base64 source.type:"base64", Anthropic URL source.type:"url" និង Responses API input_image។ លទ្ធផលដែលស្ថិតនៅខាងក្នុងជ្រៅ និង ទម្រង់ដែលមានតែសូចនាករ គឺជាសម្ភារៈសម្រាប់តម្រង combo ហើយមិនត្រូវបានស្រង់ចេញឡើយ។ រំលង ប្រសិនបើរកមិនឃើញ។
  3. កំណត់ runtime config តាមរយៈ resolveVisionBridgeRuntimeSettings() (src/shared/constants/modalityBridgeDefaults.ts)៖ settings keys ថ្មី modalityBridge* មានអាទិភាព; keys ចាស់ visionBridge* នៅតែជាជម្រើសបម្រុង មួយវដ្ត (ចន្លោះពេលសម្រាប់ rollback)។ រំលងមុនការរុករកមេឌៀណាមួយ នៅពេល bridge ត្រូវបានបិទ។
  4. ឧបករណ៍ជ្រើសរើស mode (modalityBridgeVisionMode, សូមមើលតារាងខាងក្រោម) សម្រេច ថាតើបញ្ជូនឡើងវិញ ឬពិពណ៌នា។ ការបញ្ជូនឡើងវិញត្រឡប់ modifiedPayload ដែលប្តូរតែ model ប៉ុណ្ណោះ ព្រមទាំង meta { rerouted, fromModel, toModel, imagesKept }
  5. ផ្លូវពិពណ៌នា៖ កំណត់ចំនួនរូបភាពត្រឹម maxImages, ផ្សំ prompt ដែលស្របតាមភារកិច្ច, ពិនិត្យ describe cache, ហៅម៉ូដែលចក្ខុវិស័យ ស្របពេលគ្នា (Promise.allSettled) ហើយបញ្ចូលផ្នែកអត្ថបទ [Image N]: <description> ជំនួស ទីតាំងរបស់ពួកវា។ ការពិពណ៌នាដែលបរាជ័យនឹងផ្តល់ null ហើយផ្នែករូបភាពដើមត្រូវបាន រក្សាទុក (#4012) — លើកលែងតែនៅលើផ្លូវ combo describe នៅពេលដែលការ ពិពណ៌នាទាំងអស់បរាជ័យ ដែលក្នុងករណីនោះ ខាងដើមដែលបានបញ្ជាក់ថាមិនគាំទ្រចក្ខុវិស័យ នឹងទទួលបាន stub (មិនអាចប្រើបាន — គ្មានអ្នកផ្តល់សេវាដែលគាំទ្រចក្ខុវិស័យត្រូវបានភ្ជាប់) ជំនួសវិញ (#8430)។
  6. ត្រឡប់ modifiedPayload + meta (imagesProcessed, descriptions, processingTimeMs, visionModel)។

ឧបករណ៍ជ្រើសរើស Mode (modalityBridgeVisionMode)

Mode លំនាំដើម ឥរិយាបថ
auto heuristic ចាស់ ដែលមិនបានកែប្រែ (#6640/#7204)៖ ម៉ូដែល non-combo/auto/ ត្រូវបានបញ្ជូនឡើងវិញទៅម៉ូដែលចក្ខុវិស័យល្អបំផុត លុះត្រាតែម៉ូដែលដើមមាន credential ដែលអាចប្រើបានរួចហើយ (បន្ទាប់មកនឹងពិពណ៌នា); គោលដៅ combo តែងតែពិពណ៌នា។
describe តែងតែពិពណ៌នា — block សម្រាប់ reroute ត្រូវបានរំលងទាំងស្រុង; ម៉ូដែលដែលអ្នកប្រើបានជ្រើសរើស តែងតែជាអ្នកឆ្លើយតប។
reroute បង្ខំឱ្យបញ្ជូនឡើងវិញ៖ guard សម្រាប់រក្សាម៉ូដែលដែលមាន credential ត្រូវបានរំលង។ guard សម្រាប់ credential របស់ គោលដៅ reroute នៅតែអនុវត្ត — នៅពេលគ្មានគោលដៅចក្ខុវិស័យដែលអាចប្រើបាន សំណើនឹងបន្តទៅផ្លូវពិពណ៌នា ដើម្បីកុំឱ្យរូបភាពឆៅទៅដល់ backend ដែលគាំទ្រតែអត្ថបទ (#8430)។

mode ដែលបានបង្ខំ ធ្វើ short-circuit មុន ពេល heuristic របស់ auto ដំណើរការ; ឥរិយាបថ auto គឺដូចគ្នាតាម byte ទៅនឹង guardrail មុន PR-1។

Prompt ពិពណ៌នាដែលស្របតាមភារកិច្ច (modalityBridgeVisionTaskAware)

លំនាំដើមគឺ truecomposeVisionPrompt() (visionBridgeHelpers.ts) បន្ថែម អត្ថបទនៃ សារចុងក្រោយរបស់អ្នកប្រើ (កាត់ត្រឹម 500 តួអក្សរ) ទៅក្នុង prompt ពិពណ៌នាមូលដ្ឋាន ដោយតម្រង់ការពិពណ៌នាទៅតាមអ្វីដែលអ្នកប្រើបានសួរពិតប្រាកដ (លំនាំ codex-vision-proxy) និងស្នើឱ្យម៉ូដែលចក្ខុវិស័យចម្លងអត្ថបទដែលមើលឃើញ ចេញជាអក្សរ។ នៅពេលបិទ flag — ឬគ្មានអត្ថបទពីអ្នកប្រើ — prompt មូលដ្ឋានត្រូវបានប្រើដោយមិនកែប្រែ។

សំណើដែលត្រូវគ្នាជាមួយ OpenAI ផ្ទាល់របស់ describe self-loop (callVisionModelSingle() ក្នុង visionBridgeHelpers.ts) តែងតែស្នើ image_url.detail: "high" — ដោយគ្មានលក្ខខណ្ឌ សម្រាប់គ្រប់ caller/provider ទាំងអស់ ហើយមិនពឹងផ្អែកលើសញ្ញាណាមួយពី client ទេ។ ការយកគំរូក្នុងកម្រិតលម្អិតទាបធ្វើឱ្យភាពត្រឹមត្រូវនៃ OCR ថយចុះ ជាពិសេសសម្រាប់កិច្ចការ ចម្លងអត្ថបទដែល prompt នេះស្នើសុំ ដូច្នេះ describe call ខ្លួនវាតែងតែស្នើកម្រិតលម្អិតខ្ពស់ ដោយមិនគិតពីកម្រិតលម្អិតដែលសំណើចូលដើមបានប្រើឡើយ។ វាប៉ះពាល់តែទៅលើ body នៃ សំណើ describe ខាងក្នុងប៉ុណ្ណោះ; វាមិនផ្លាស់ប្ដូររបៀបដែល OmniRoute បញ្ជូនបន្ត image_url.detail ផ្ទាល់របស់ caller នៅលើសំណើចម្បងទេ — តម្លៃលំនាំដើមនោះត្រូវបានអនុវត្តដាច់ដោយឡែក ហើយអនុវត្តតែសម្រាប់ OpenCode clients ដែលត្រូវបានរកឃើញប៉ុណ្ណោះ ក្នុង defaultImageDetail() (open-sse/handlers/chatCore/upstreamBody.ts)។ Branch ជា wire format របស់ Anthropic នៃ describe self-loop មិនមាន field detail ទេ ហើយមិនរងផលប៉ះពាល់ ដោយតម្លៃលំនាំដើមណាមួយក្នុងចំណោមទាំងពីរនេះឡើយ។

កម្រិតអតិបរមានៃ output របស់ describe (modalityBridgeVisionMaxChars)

Key លំនាំដើម ជួរ
modalityBridgeVisionMaxChars 0 0 ឬ 10050000

0 (លំនាំដើម) មានន័យថា គ្មានកម្រិតអតិបរមា — សេចក្ដីពិពណ៌នាដែលត្រឡប់ដោយ callVisionModel() ត្រូវបានបញ្ជូនបន្តដោយមិនកែប្រែ ដើម្បីរក្សាឥរិយាបថដែលមានស្រាប់។ តម្លៃណាមួយក្នុងជួរ 10050000 នឹងកាត់សេចក្ដីពិពណ៌នា និងបន្ថែមបច្ច័យ មុនពេលវាត្រូវបានបញ្ចូលត្រឡប់ជាទម្រង់ [Image N]: <description> (VisionBridgeGuardrail.preCall() ក្នុង src/lib/guardrails/visionBridge.ts)។ ដំឡើងតម្លៃនេះសម្រាប់កិច្ចការ OCR ដែលមានព័ត៌មានលម្អិតច្រើន ដែល downstream model ត្រូវការអត្ថបទចម្លងពេញលេញ; បន្ថយវាដើម្បីកំណត់ការប្រើប្រាស់ token លើ vision models ដែលបង្កើតអត្ថបទវែង។ Field នៅលើ dashboard ស្ថិតក្នុង panel Advanced នៃផ្ទាំង Vision (modality-bridge-max-chars ក្នុង ModalityBridgeVisionTab.tsx) ហើយកែតម្លៃណាមួយ ចន្លោះពី 1 ដល់ 99 ឱ្យឡើងដល់កម្រិតទាបបំផុត 100 ខណៈដែលរក្សា 0 ដែលបានកំណត់ ជាក់លាក់ឱ្យនៅដដែល — 0 គឺជាតម្លៃ Zod ត្រឹមត្រូវដោយខ្លួនឯង (z.union([z.literal(0), z.number().int().min(100).max(50000)])) មិនមែនគ្រាន់តែជា តម្លៃលំនាំដើម "មិនបានកំណត់" នោះទេ។

Cache របស់ describe (modalityBridge/bridgeCache.ts)

Cache LRU + TTL ក្នុង memory សម្រាប់ outputs របស់ describe ដែលត្រូវបានចែករំលែក ទូទាំង process។ Key = sha256(imageRef + composedPrompt + configuredBridgeModel) ដោយប្រើ length-prefix framing (គ្មាន field-boundary collisions)។ សមាសភាគ model គឺជា bridge model ដែលបានកំណត់រចនាសម្ព័ន្ធ configured មិនមែន model ដែលពិតជាបាន ឆ្លើយតបទេ — callVisionModel អាច fallback នៅខាងក្នុង ហើយការបង្កើត key តាម attempt នីមួយៗ នឹងធ្វើឱ្យ cache បែកខ្ញែក។ Describe ដែលបរាជ័យមិនត្រូវបានដាក់ក្នុង cache ទេ។ ការកំណត់៖

Key លំនាំដើម ជួរ
modalityBridgeCacheEnabled true
modalityBridgeCacheTtlMinutes 60 11440
modalityBridgeCacheMaxEntries 200 105000

ការធ្វើ normalization រូបភាពពីចម្ងាយ (self-loop describe/base64 fetch)

នៅពេល bridge ទាញយករូបភាព remote ដោយខ្លួនវា — Anthropic describe self-call និងការបម្លែងទៅជា base64 សម្រាប់ claude-wire-format (ensureBase64ImagesForClaudeWire) ដែលទាំងពីរប្រើ fetchRemoteImageAsDataUri() ក្នុង visionBridgeHelpers.ts — data URI ដែលទទួលបាន ត្រូវបានបញ្ជូនកាត់ normalizeDataUri() (open-sse/utils/imageNormalize.ts) មុនពេលបង្កប់ក្នុងសំណើទៅ vision model។ រូបភាពដែលមានទំហំធំពេកត្រូវបានបង្រួមមាត្រដ្ឋានឱ្យជ្រុងវែងមានប្រវែង 2048px (ត្រូវគ្នានឹងកម្រិតបង្រួមទំហំដែល OpenAI/Anthropic បានអនុវត្តរួចហើយ នៅ server-side) ដែលកាត់បន្ថយចំនួន bytes/latency នៃការផ្ទុកឡើង ដោយមិនផ្លាស់ប្ដូរ អ្វីដែល vision model មើលឃើញ។ ការកែទំហំប្រើ sharp ដែលត្រូវបានផ្ទុកតាមរយៈ dynamic import៖ នៅលើ platform ដែល native binary របស់វាមិនអាចផ្ទុកបាន normalizeDataUri() មិនដែល throw ទេ — វា fallback ទៅការបញ្ជូន bytes ដើម ដោយមិនកែប្រែ ដូច្នេះផ្លូវ describe/base64-conversion តែងតែអាចដំណើរការបាន។ Bytes ដែលមិនមែនជារូបភាព (ការទាញយកដែលមិនបានត្រឡប់រូបភាពដែលអាច decode បាន) ក៏ត្រូវបានបញ្ជូនបន្តដោយមិនកែប្រែផងដែរ។ Normalization នេះមានវិសាលភាពត្រឹមតែ រូបភាពដែល bridge ទាញយកសម្រាប់ self-call ផ្ទាល់របស់វាប៉ុណ្ណោះ — វាមិនត្រូវបានអនុវត្ត លើ raw passthrough payload របស់ caller ឡើយ ដែលស្របនឹងគោលការណ៍កែប្រែតែនៅពេល opt-in ប៉ុណ្ណោះ (Hard Rule #20)។

Schema នៃការកំណត់ + migration

Keys ថ្មី modalityBridge* ត្រូវបាន validate ដោយ Zod ក្នុង updateSettingsSchema (src/shared/validation/settingsSchemas.ts)៖ modalityBridgeVisionEnabled, modalityBridgeVisionMode, modalityBridgeVisionModel, modalityBridgeVisionTaskAware, modalityBridgeVisionPrompt, modalityBridgeVisionTimeout, modalityBridgeVisionMaxImages, modalityBridgeVisionMaxChars, ក្រុមទាំងបី modalityBridgeCache* និងក្រុម modalityBridgeAudio* ដែលប្រើដោយ Audio Bridge។ Migration 141_modality_bridge_settings.sql ចម្លងតម្លៃ legacy visionBridge* ដែលមានស្រាប់ ទៅ keys ថ្មីដែលត្រូវគ្នា (មានលក្ខណៈ idempotent និងមិនដែលសរសេរជាន់លើតម្លៃ modalityBridge* ដែល operator បានកំណត់ទេ); keys legacy នៅតែត្រូវបានទទួលយកជា read fallback សម្រាប់ release cycle មួយ។

Transparency header + ស្ថិតិ

Responses ដែលត្រូវបានបម្លែងដោយ describe មាន x-omniroute-modality-bridge: image->text;model=<visionModel>;parts=<n> (បង្កើតដោយ buildModalityBridgeHeader() ក្នុង modalityBridge/bridgeStats.ts និងបញ្ចូលដោយ withModalityBridgeHeader() ក្នុង src/sse/handlers/chatHelpers.ts)។ សំណើដែលត្រូវបាន reroute មិនមាន header ទេ — payload មិនត្រូវបានកែប្រែ ហើយ ការប្ដូរ model អាចមើលឃើញរួចហើយក្នុង field model នៃ response body។

GET /api/modality-bridge/stats (management auth ក្នុងកម្រិតដូចគ្នានឹង GET /api/settings) ត្រឡប់ counters ក្នុង memory តាម modality នីមួយៗ { attempts, successes, bridged, cacheHits, failures, totalLatencyMs, latencySamples, averageLatencyMs, lastUsedAt } សម្រាប់ vision, audio និង videoaverageLatencyMs ប្រើ latencySamples ជាភាគបែង មិនមែន attempts ទាំងអស់ទេ; ប្រតិបត្តិការដែលគ្មាន timing មិនបង្កើត sample សូន្យមីលីវិនាទីក្លែងក្លាយទេ។ bridged នៅតែជាឈ្មោះ alias ដែលត្រូវគ្នានឹងកំណែចាស់ សម្រាប់ conversions ដែលជោគជ័យ; attempts ដែលបរាជ័យមិនបង្កើនវាទេ។ Counters ត្រូវបានកំណត់ឡើងវិញនៅពេល process ចាប់ផ្ដើមឡើងវិញតាមការរចនា (telemetry មិនមែន accounting)។

ការកំណត់រចនាសម្ព័ន្ធ Dashboard

ទំព័រផ្ទាំងគ្រប់គ្រងសម្រាប់មុខងារនេះគឺ /dashboard/settings/modality-bridge។ ផ្ទាំង Vision, Audio, និង Video ដែលអាចចូលប្រើតាម URL រក្សាប៉ារ៉ាម៉ែត្រសំណួរ ខណៈពេលប្ដូរតម្លៃ tab។ ផ្ទាំង Vision ផ្តល់ជូនការបើកដំណើរការ, របៀប, ការជ្រើសរើសម៉ូដែល (រួមទាំងលំនាំដើម ស្វ័យប្រវត្តិ), ការបង្កើត prompt ដោយយល់ដឹងពីកិច្ចការ, ដែនកំណត់កម្រិតខ្ពស់សម្រាប់ អស់ពេល/រូបភាព/ប្រវែងការពិពណ៌នា/ឃ្លាំងសម្ងាត់, កម្មវិធីរាប់ពេលដំណើរការ, និងសំណើគំរូដែលមានការការពារ។ ផ្ទាំង Audio ក៏ដំណើរការផ្ទាល់ផងដែរ៖ វាផ្តល់ជូន ការបើកដំណើរការ, ឧបករណ៍ជ្រើសរើសម៉ូដែលសម្រាប់តែ STT ជាមួយ Auto, ដែនកំណត់ អស់ពេល/ប្រវែងឃ្លីបអតិបរមា, កម្មវិធីរាប់សំឡេង, និងការធ្វើតេស្តគំរូ input_audio។ ផ្ទាំង Video មានមុខងារពេញលេញ៖ វារាយការណ៍ស្ថានភាពពេលដំណើរការរបស់ FFmpeg/ffprobe — មួយក្នុងចំណោមស្ថានភាព UI ជាក់លាក់ចំនួនបួន (unknown ខណៈពេល ការស្ទង់កំពុងដំណើរការ ឬមិនអាចបញ្ចប់បាន, restricted នៅលើម៉ាស៊ីនផ្ទុក ផ្ទាំងគ្រប់គ្រងដែលមិនមែនជា loopback ដែលការស្ទង់ត្រូវបានរំលងនៅផ្នែក client, unavailable បន្ទាប់ពីបានស្ទង់ និងបញ្ជាក់ថាមិនមាន, ឬ available ជាមួយកំណែ FFmpeg/ffprobe) — រក្សាទុកដែនកំណត់បើកដំណើរការ/ម៉ូដែល/ហ្វ្រេម/វីដេអូ/អស់ពេល, ត្រងឧបករណ៍ជ្រើសរើសម៉ូដែលឱ្យនៅសល់តែម៉ូដែលដែលគាំទ្រ vision, និងផ្តល់ជូនកម្មវិធីរាប់វីដេអូ។

កាត Vision Bridge ចាស់នៅក្រោមការកំណត់ AI គឺជាតំណភាពឆបគ្នាទៅកាន់ ទំព័រថ្មី; វាលែងកាន់កាប់ច្បាប់ចម្លងទីពីរនៃសំណុំបែបបទទៀតហើយ។ Media Providers ក៏ភ្ជាប់លំហូរការងារ Image-to-Text និង Speech-to-Text ទៅផ្ទាំង Modality Bridge ដែលត្រូវគ្នា ដោយមិនលុប playground របស់ Speech-to-Text ដែលមានស្រាប់ឡើយ។

ការរំលងការអនុញ្ញាត self-loop: នៅពេលការហៅ describe ត្រូវបានបញ្ជូនតាម /v1 self-loop ផ្ទាល់របស់ OmniRoute (ម៉ូដែលអ្នកផ្តល់សេវាដែលមិនមែនជាស្តង់ដារ), សំណើរងផ្ញើ x-omniroute-admission-bypass: internal ហើយត្រូវបានផ្ទៀងផ្ទាត់ ដោយប្រើព័ត៌មានសម្ងាត់ self-loop ដែលបានដោះស្រាយ — sentinel sk_omniroute មូលដ្ឋានក្នុងរបៀប local ឬ env key OMNIROUTE_API_KEY / ROUTER_API_KEY ដែលកំណត់ដោយប្រតិបត្តិករ (#1350) ដូច្នេះការដាក់ឱ្យដំណើរការដែលមាន REQUIRE_API_KEY=true នៅតែអាចដំណើរការការហៅ describe បាន។ ការរំលងនេះ ត្រូវបានទទួលស្គាល់តែសម្រាប់ព័ត៌មានសម្ងាត់ជាក់លាក់ទាំងនោះប៉ុណ្ណោះ ដូច្នេះ client ខាងក្រៅមិនអាចប្រើ header ដើម្បីរំលងការអនុញ្ញាតបានទេ។

លំនាំដើមចាស់ស្ថិតនៅក្នុង src/shared/constants/visionBridgeDefaults.ts; លំនាំដើមថ្មីសម្រាប់របៀប/ការយល់ដឹងពីកិច្ចការ/ឃ្លាំងសម្ងាត់ និងឧបករណ៍ដោះស្រាយ ការកំណត់ ស្ថិតនៅក្នុង src/shared/constants/modalityBridgeDefaults.ts។ guardrail ផ្តល់ជម្រើស constructor deps ដើម្បីឱ្យការធ្វើតេស្តអាចចាក់បញ្ចូល ការអនុវត្តក្លែងក្លាយរបស់ getSettings និង callVisionModel

Audio Bridge (audioBridge.ts) — Modality Bridge PR-3

ស្ទាក់ចាប់សំណើ chat ដែលមានសំឡេង មុនពេលសំណើទាំងនោះទៅដល់គោលដៅដែលមិនត្រូវបាន ដឹងថាអាចទទួលយកការបញ្ចូលសំឡេង។ វាមិនដែលបញ្ជូនសំណើ chat ទៅផ្លូវផ្សេងឡើយ៖ ផ្នែកសំឡេងត្រូវបានបម្លែងជាអត្ថបទតាមរយៈ endpoint multipart ដែលឆបគ្នាជាមួយ OpenAI ដែលមានស្រាប់ ហើយម៉ូដែល chat ដែលបានជ្រើសរើសបន្តជាមួយប្រតិចារិកអត្ថបទ។

លំហូរ៖

  1. ដោះស្រាយ supportsAudio តាមរយៈ getResolvedModelCapabilities()។ metadata ច្បាស់លាស់ពី provider-registry មានអាទិភាព បន្ទាប់មក metadata ម៉ូដែលថេរ ហើយបន្ទាប់មក modalities_input ដែលបានធ្វើសមកាលកម្ម។ បញ្ជី input ដែលបាន ប្រកាសដោយគ្មាន audio គឺ false; ប្រសិនបើគ្មានភស្តុតាងសមត្ថភាព តម្លៃនៅជា null។ ទាំង false និង null បើកដំណើរការ bridge បែបប្រុងប្រយ័ត្ន ខណៈ true រំលងវា។
  2. ដោះស្រាយការកំណត់ modalityBridgeAudio* ហើយស្រង់ផ្នែកសំឡេងកម្រិតកំពូល ដែលអាច splice បានពីគ្រប់សារ តាមរយៈ detector detectMediaParts() រួម។ ទម្រង់ wire ដែលគាំទ្រគឺ OpenAI input_audio, audio_url, និង source.media_type: "audio/*"។ សំឡេងដែលដាក់ជាន់ខាងក្នុងត្រូវបានរកឃើញ សម្រាប់ការកំណត់ផ្លូវ ប៉ុន្តែមិនត្រូវបានយកចេញដោយផ្លូវ splice ទេ។ បរិមាណការងារ ត្រូវបានកំណត់ដោយ modalityBridgeAudioMaxClips; ផ្នែកក្រោយៗនៅដដែល។
  3. គោរពតាម provider/model ដែលបានកំណត់ ឬអនុញ្ញាតឱ្យ selectAudioBridgeModel() ឆ្លងកាត់ AUDIO_TRANSCRIPTION_PROVIDERS តាមលំដាប់ catalog ថេរ ហើយជ្រើសរើសម៉ូដែលដំបូងដែលមានព័ត៌មានសម្ងាត់ អ្នកផ្តល់សេវាសកម្មដែលអាចប្រើបាន។
  4. callAudioTranscription() បម្លែងសំឡេង base64/data-URI ទៅជា file multipart ឬទាញយក audio_url ពីចម្ងាយ តាមរយៈឧបករណ៍ការពារ outbound សម្រាប់សាធារណៈតែប៉ុណ្ណោះ ជាមួយ DNS pinning និងដែនកំណត់ 25 MB។ បន្ទាប់មក វា POSTs ឯកសារ និងម៉ូដែលដែលបានជ្រើសរើសទៅកាន់ self-loop /v1/audio/transcriptions មូលដ្ឋាន ដោយផ្ទៀងផ្ទាត់ជាមួយ resolveSelfLoopBearer()។ route ប្រតិចារិកដែលមានស្រាប់ អនុវត្តការស្វែងរក ព័ត៌មានសម្ងាត់, ការគ្រប់គ្រង cooldown/rate-limit, និងការបញ្ជូនទៅអ្នកផ្តល់សេវា តាមធម្មតា។
  5. ការហៅដែលជោគជ័យជំនួសផ្នែករបស់វាដោយ [Audio N]: <transcript>។ ការហៅ ដំណើរការជាមួយ Promise.allSettled៖ ការបរាជ័យនីមួយៗរក្សាទុកផ្នែកសំឡេង ដើមនោះ (#4012 contract)។ ប្រសិនបើការហៅទាំងអស់បរាជ័យ ហើយគោលដៅត្រូវបាន បញ្ជាក់ថា supportsAudio === false ផ្នែកទាំងនោះក្លាយជា [Audio N]: (មិនអាចប្រើបាន — គ្មានអ្នកផ្តល់សេវា STT បានភ្ជាប់) (#8430 contract)។ សម្រាប់គោលដៅដែលមិនស្គាល់ (null) លទ្ធផលដែលបរាជ័យទាំងអស់នៅដដែល។ គោលដៅ text-only ដែលបានបញ្ជាក់ និងគ្មានព័ត៌មានសម្ងាត់ STT អាចប្រើបាន ទទួល stub ច្បាស់លាស់ដូចគ្នា ដោយមិនធ្វើការហៅបណ្ដាញ។

ប្រតិចារិកដែលជោគជ័យប្រើឃ្លាំងសម្ងាត់ LRU/TTL របស់ Modality Bridge ទូទាំង process។ key ផ្សំឡើងពីឯកសារយោងសំឡេង, ស្លាកប្រតិបត្តិការ audio-transcription ថេរ, និងម៉ូដែល STT ដែលបានជ្រើសរើស; ការបរាជ័យមិនត្រូវបាន រក្សាទុកក្នុងឃ្លាំងសម្ងាត់ឡើយ។ ការប៉ុនប៉ងសំឡេងធ្វើបច្ចុប្បន្នភាពកម្មវិធីរាប់រួម bridged, cacheHits, failures, និង lastUsedAt។ response ដែលបានបម្លែង មាន x-omniroute-modality-bridge: audio->text;model=<sttModel>;parts=<n>; សំណើដែលមិនបានកែប្រែមិនទទួលបាន segment របស់ Audio Bridge ទេ។

ការកំណត់ពេលដំណើរការត្រូវបានគាំទ្រដោយ DB និងផ្ទៀងផ្ទាត់ដោយ Zod៖

Key លំនាំដើម ជួរ
modalityBridgeAudioEnabled true
modalityBridgeAudioModel "" Auto ឬ STT ID
modalityBridgeAudioTimeout 60000 1000300000
modalityBridgeAudioMaxClips 3 110

ឃ្លាំងសម្ងាត់រួមនៅតែត្រូវបានគ្រប់គ្រងដោយ modalityBridgeCacheEnabled, modalityBridgeCacheTtlMinutes, និង modalityBridgeCacheMaxEntries

Video Bridge (videoBridge.ts, videoBridgePipeline.ts)

ស្ទាក់ចាប់ផ្នែកវីដេអូកម្រិតកំពូលនៅក្នុង Chat Completions messages និង Responses API input មុនពេលគោលដៅដែលមិនត្រូវបានដឹងថាមានការគាំទ្រវីដេអូដើមត្រូវបានហៅ។ ទម្រង់ដែលគាំទ្រមាន input_video, video_url, video_source, HTTPS URLs, និង data URIs ប្រភេទ data:video/*;base64,...។ ឈ្មោះឯកសារធម្មតានៅក្នុងអត្ថបទមិនត្រូវបានចាត់ទុក ជាវីដេអូទេ។

VideoBridgeGuardrail.preCall (videoBridge.ts) គ្រប់គ្រងការឆ្លងកាត់សំណើ ការត្រួតពិនិត្យសមត្ថភាព/គោលការណ៍ ការប្រមូលផ្តុំតាមសំណើនីមួយៗ និង payload នៃការឆ្លើយតប។ ការងារតាមវីដេអូនីមួយៗ — ការទទួលយក ការរក្សាទុក cache នៃលទ្ធផលទាំងមូល ការពិពណ៌នា frame sequence (ដែលបញ្ចូល transcript សំឡេងណាមួយដែលអ្នកហៅបានប្រកាស) និង metrics/abort/cleanup តាមការព្យាយាមនីមួយៗ — ត្រូវបានលាក់នៅពីក្រោយ processVideoPart ក្នុង videoBridgePipeline.ts ដែលត្រូវបានហៅម្តងសម្រាប់ផ្នែកវីដេអូនីមួយៗនៅក្នុង loop របស់ preCall។ ម៉ូឌុលនោះក៏កំណត់ព្រំដែន port ជាក់លាក់ VideoMediaBrokerPort (ការទទួលយក bytes និងការស្រង់ frames ដែលបានយកគំរូ), VideoAudioTranscriptionPort (ការបញ្ចូល transcript សំឡេងដែលអ្នកហៅបានប្រកាសជាមួយ captions ដែលបានយកគំរូ) និង VideoDrilldownPort (ព្រំដែនរក្សាទុក frame drill-down; មិនទាន់បានតភ្ជាប់ ទៅក្នុង processVideoPart ទេ — បច្ចុប្បន្នមានតែ route ដាច់ដោយឡែក /api/modality-bridge/video/drilldown ប៉ុណ្ណោះដែលសរសេរ entries សម្រាប់ drill-down)។

ផ្លូវសំណើសាធារណៈ /v1 មិនដែល import ឬហៅ subprocess ទេ។ វីដេអូពីចម្ងាយ ត្រូវបានទាញយកក្រោមដែនកំណត់ 50 MiB; វីដេអូ base64 ខាងក្នុងមាន កម្រិតអតិបរមា conservative 36 MiB ដែលបាន decode ក្នុងមួយវីដេអូ ដើម្បីឱ្យ model/messages/framing envelope អាចស្ថិតនៅក្នុងដែនកំណត់ទទួលសំណើ JSON សាធារណៈ 50 MiB។ ប្រវែង inline និងការប៉ាន់ស្មានទំហំដែលបាន decode ត្រូវបានត្រួតពិនិត្យមុន allocation។ HTTPS ត្រូវបានទាមទារនៅ URL ពីចម្ងាយដំបូង និងគ្រប់ redirect ដោយប្រើ outbound guard ដែលអនុញ្ញាតតែសាធារណៈដែលមានស្រាប់ ជាមួយ DNS pinning។ បន្ទាប់មក bytes ឆ្លងកាត់ព្រំដែន broker ខាងក្នុងពិតប្រាកដ POST /api/modality-bridge/video/extract។ Route នោះមានទាំង LOCAL_ONLY និង SPAWN_CAPABLE ទទួលយកតែសំណើ trusted-loopback ដែលបានផ្ទៀងផ្ទាត់តាម process នីមួយៗ ហើយមិនដែលទទួល URL, filesystem path, executable ឬបញ្ជី arguments ទេ។ Pipeline កំណត់ទំហំ body របស់ API និង body reader ជាបន្តបន្ទាប់របស់ handler អនុវត្តដោយឯករាជ្យនូវកម្រិតបញ្ចូល broker 50 MiB។ Queue មានដែនកំណត់របស់វា ដំណើរការ extraction ម្តងមួយ អនុញ្ញាតការងាររង់ចាំចំនួនបួន និងកំណត់ pending input ត្រឹម 100 MiB។

នៅក្នុង broker, ffprobe អានឯកសារមូលដ្ឋានឯកជនមួយ; បញ្ជីអនុញ្ញាត format ថេរ មិនរួមបញ្ចូល format ប្រភេទ playlist និង manifest ទេ។ សម្រាប់ container ត្រកូល MOV ដែលបានអនុញ្ញាត external MOV data references នៅតែត្រូវបានបិទតាមលំនាំដើម ហើយ command ថេរមិនបើកឱ្យប្រើវាទេ។ ទាំង ffprobe និង ffmpeg ប្រើ បញ្ជីអនុញ្ញាត protocol តែ file ប៉ុណ្ណោះ, thread មួយ, argument arrays ថេរ, គ្មាន shell ហើយ executables ត្រូវបានស្វែងរកពី PATH។ Attached-picture cover streams មិនមែនជា ជម្រើសដែលអាចចាក់បានទេ។ Playable streams ទាំងអស់ត្រូវតែបំពេញតាមដែនកំណត់ ហើយ default stream ជាក់លាក់មួយត្រូវបានផ្តល់អាទិភាពមុន deterministic lowest-index fallback។ វីដេអូត្រូវបានកំណត់ត្រឹម 600 វិនាទី, 8,192 pixels ក្នុងមួយវិមាត្រ និង 33,554,432 source pixels។ FFmpeg យកគំរូ midpoint JPEG frames ចំនួន 116, បន្ថយមាត្រដ្ឋាន ជ្រុងវែងឱ្យនៅត្រឹមអតិបរមា 1,024 pixels ដោយមិនពង្រីក inputs ដែលតូចជាង និង មិនដែលទទួល URL ទេ។ ការយកគំរូគឺ uniform តាមលំនាំដើម។ គោលការណ៍ជាជម្រើស scene_aware និងគោលការណ៍ពិសោធន៍ segment_aware អនុវត្ត FFmpeg pass ថេរបន្ថែមមួយ លើ local stream ដែលបាន validate រួច ជ្រើសរើស scene timestamps របស់ showinfo ដែលមានដែនកំណត់ ហើយ fallback ដោយ deterministic ទៅ midpoints បែប uniform ដូចគ្នា នៅពេល detector បរាជ័យ, timeout, output ខុសទម្រង់ ឬ candidate set ទទេ។ Segment-aware mode បែងចែក midpoint samples តាមសមាមាត្រទៅនឹង scene intervals ដែលបាន validate; ភស្តុតាង segment-aware និងឥរិយាបថ fallback ត្រូវបានពិពណ៌នាលម្អិតខាងក្រោម។ កម្រិតអតិបរមាដាច់ខាត 16-frame ត្រូវបាន អនុវត្តបន្ទាប់ពីការជ្រើសរើសក្នុងគ្រប់គោលការណ៍។ នៅពេលសំណើ scene-aware មាន budget តែ មួយ frame វាប្រើ uniform midpoint នៃ full-video ឬ focus window ដែលសកម្ម ហើយរាយការណ៍ policyEffective: uniform: scene frame តែមួយដែលបានជ្រើសរើស មិនអាចរក្សាចុងទាំងពីរនៃពេលវេលាបានទេ។ អ្នកហៅអាចផ្តល់ជាជម្រើសនូវ focus window កំណត់ (start/end វិនាទី); bounds ត្រូវបាន clamp តាម media duration, windows ដែលបញ្ច្រាស ឬមិន finite ត្រូវបានបដិសេធ ហើយគោលការណ៍ sampling ទាំងអស់ ត្រូវបានអនុវត្តតែនៅក្នុង interval ដែលបាន normalize ប៉ុណ្ណោះ។ Window ដែលបានបង្កើត ត្រូវបានបញ្ចូលក្នុង sampling metadata និងក្នុង untrusted description prefix ដើម្បីឱ្យ downstream models អាចបែងចែក excerpt ដែលបាន focus ពី timeline ទាំងមូល។

Semantic caption focus គឺជាការកំណត់ជាក់លាក់ដាច់ដោយឡែកមួយ។ Analysis mode លំនាំដើម full រក្សា frame prompt ដែលមានស្រាប់ ហើយមិនដែលបញ្ជូនអត្ថបទសំណើទៅ caption model ទេ។ នៅក្នុង mode focused bridge អានតែ text/input_text ចុងក្រោយបំផុតដែលមិនទទេ និងត្រូវបានសរសេរដោយ user ពី Chat ឬ Responses container ដូចគ្នា, normalize វាទៅ NFC, បង្រួម control characters និង whitespace ហើយកំណត់វាត្រឹម 500 Unicode code points។ លទ្ធផលទទេនឹង fallback ទៅ full prompt ដដែលពិតប្រាកដ។ Hint ដែលអាចប្រើបានត្រូវបាន serialize ជា JSON ក្នុង block dedicated untrusted-user-context មួយ ហើយអាចត្រឹមតែផ្តល់អាទិភាព ដល់ព័ត៌មានលម្អិតដែលអាចសង្កេតបានប៉ុណ្ណោះ; វាមិនអាចបដិសេធការព្រមានដាច់ដោយឡែកដែលហាម ការធ្វើតាមសេចក្តីណែនាំដែលអាចមើលឃើញ ឬឮនៅក្នុង media បានទេ។ Textual focus មិនដែលសន្និដ្ឋាន start/end ឬផ្លាស់ប្តូរ temporal sampler ទេ។

ភស្តុតាង structural segment FU-07

segment_aware ប្រើ pre-analysis pass មានដែនកំណត់មួយលើ local video stream ដែលបាន validate រួច។ Fixed filter chain ដំបូងបន្ថយមាត្រដ្ឋានឱ្យមានទទឹងអតិបរមា 320 pixels, រកឃើញ scene changes និង frozen intervals ហើយបន្ទាប់មកយកគំរូ 1 frame ក្នុងមួយវិនាទី សម្រាប់ blur, average luma និង spatial/temporal information។ Pass នេះត្រូវបានកំណត់ ត្រឹម 600 structural samples, FFmpeg/filter thread មួយ, protocol តែ file និង container allowlists ដូចគ្នា, ដែនកំណត់ process-output 1 MiB និងរយៈពេលអតិបរមា 30 វិនាទីនៅក្នុង abort/deadline រួមរបស់ broker។ វាមិនដែលទទួល command, filter, path ឬ URL ពីសំណើទេ។

តម្លៃរចនាសម្ព័ន្ធគឺជាភស្តុតាងនៃការយកសំណាកបែបកំណត់ជាមុន មិនមែនជាការយល់ដឹងអំពីវីដេអូតាមន័យទេ។ តម្លៃទាំងនេះមិនសន្និដ្ឋានអំពីប្រធានបទ សកម្មភាព ចំណងជើងរូបភាព សុន្ទរកថា ឬបំណងរបស់អ្នកប្រើឡើយ។ ព្រំដែនឈុតឆាក និងព្រំដែនការកកបង្កើតជាផ្នែកៗ។ វិសាលភាពនៃការកក ភាពព្រិល កម្រិតពន្លឺ ព័ត៌មានលម្អិតលំហ និងការផ្លាស់ប្តូរតាមពេលវេលា មានឥទ្ធិពលតែលើរបៀបបែងចែកថវិកាដែលមានស្រាប់ពី 116 ស៊ុមប៉ុណ្ណោះ។ ផ្នែកដែលកកទាំងស្រុងត្រូវបានកំណត់ត្រឹមមួយស៊ុម ខណៈផ្នែកដែលមិនកកប្រកួតគ្នាសម្រាប់ថវិកាដែលនៅសល់។ នៅពេលចំនួនព្រំដែនច្រើនជាងចំនួនស៊ុម ការគ្របដណ្តប់បន្ទាត់ពេលវេលាដោយស្មើគ្នាត្រូវបានរក្សាទុក ដើម្បីឱ្យការកាត់ឈុតលឿនៗនៅដើមមិនអាចបិទបាំងផ្នែកវែងនៅខាងចុងបាន។ ព្រំដែនឈុតឆាកដែលស្ថិតក្នុងកម្រិតគុណភាពបង្ហាញនៃការវិភាគ 1 វិនាទីពីព្រំដែនការកក ត្រូវបានបញ្ចូលគ្នា។

តម្រងដែលបាត់ ភស្តុតាងមិនត្រឹមត្រូវ/ទទេ កំហុសកម្មវិធីរាវរក ឬការអស់ពេលនៃការវិភាគជាមុនដែលមានដែនកំណត់ នឹងបរាជ័យដោយបើកចំហទៅរកគោលការណ៍ចំណុចកណ្ដាលស្មើគ្នាពិតប្រាកដ។ ការបោះបង់ពីអ្នកហៅ ឬកាលកំណត់របស់ broker មិនបរាជ័យដោយបើកចំហទេ៖ វាបញ្ចប់ subprocess ដែលកំពុងដំណើរការ រារាំងការស្រង់ស៊ុមនៅពេលក្រោយ ហើយលុបមែកធាងបណ្ដោះអាសន្នឯកជននៅក្នុង finally

scripts/perf/video-bridge-fu07-eval.ts បង្កើត fixtures FFmpeg ពិតប្រាកដបែបកំណត់ជាមុន សម្រាប់ការសន្សំចំនួនការហៅបង្កើតចំណងជើងរូបភាពក្រោយការលុបស្ទួន ការបែងចែកថវិកាសម្រាប់ចលនាក្រាស់ ភស្តុតាងភាពព្រិល/កម្រិតពន្លឺ/SI-TI ការកាត់ឈុតលឿនជាមួយផ្នែកខាងចុងវែង និងលទ្ធផលវិជ្ជមានមិនពិតពីការរលាយបន្តិចម្តងៗ។ វាកត់ត្រារយៈពេលជាក់ស្តែងនៃការវិភាគជាមុន ហើយនៅកន្លែងដែលមាន /usr/bin/time វាក៏កត់ត្រា CPU របស់ដំណើរការរង និង RSS អតិបរមាផងដែរ។ ការត្រួតពិនិត្យគុណភាពរបស់វាគ្រាន់តែជាឧបករណ៍វិនិច្ឆ័យតាមរចនាសម្ព័ន្ធប៉ុណ្ណោះ។ គុណភាពគំរូបង្កើតចំណងជើងរូបភាពពិតប្រាកដនៅតែជា HOLD ព្រោះ harness នេះមិនមាន endpoint ដែលបានអនុញ្ញាត ឬកម្មវិធីវិនិច្ឆ័យថេរទេ។ ការសន្សំប្រាក់ក៏នៅតែជា HOLD ដែរ លុះត្រាតែ --caption-cost-per-call-usd ផ្ដល់ការប៉ាន់ស្មានថ្លៃក្នុងមួយការហៅដែលវិជ្ជមានយ៉ាងច្បាស់។ ស្គ្រីបនេះមិនដែលប្រឌិតលទ្ធផលទាំងពីរនោះឡើយ។

ស៊ុមនីមួយៗត្រូវបានកំណត់ត្រឹម 4 MiB ស៊ុមដើមទាំងអស់រួមគ្នាត្រឹម 23 MiB និងការឆ្លើយតបរបស់ broker ដែលបានធ្វើ serialization ត្រឹម 32 MiB។ ថតបណ្ដោះអាសន្នឯកជនត្រូវបានលុបនៅក្នុង finally។ OmniRoute មិនរួមបញ្ចូល FFmpeg មកជាមួយទេ ហើយក៏មិនទទួលយកទីតាំង executable ផ្ទាល់ខ្លួនដែរ។ មុនពេលបង្កើតចំណងជើងរូបភាព bridge អនុវត្តដំណាក់កាលលុបស្ទួនតាមរូបភាពបែបប្រុងប្រយ័ត្ន៖ JPEG នីមួយៗត្រូវបានបន្ថយទៅជា buffer ពណ៌ប្រផេះទំហំ 16×16 ហើយត្រូវបានប្រៀបធៀបតែជាមួយស៊ុមចុងក្រោយដែលបានរក្សាទុកប៉ុណ្ណោះ។ សម្រាប់ថវិកាបង្កើតចំណងជើងរូបភាពដែលបានស្នើលើសពីមួយស៊ុម ការស្រង់ផ្ដល់ក្រុមបេក្ខភាពមានដែនកំណត់ដែលមានចំនួនរហូតដល់ពីរដងនៃថវិកានោះ និងមិនលើសពី 16 ស៊ុមឡើយ។ ដែនកំណត់ដែលបានស្នើត្រូវបានអនុវត្តតែក្រោយពេលលុបស្ទួនប៉ុណ្ណោះ ដោយរក្សាបេក្ខភាពដំបូង និងចុងក្រោយដែលបានជ្រើសរើស ក្នុងអំឡុងពេលសម្រកចុងក្រោយ នៅពេលថវិកាមានយ៉ាងហោចណាស់ពីរ។ គោលការណ៍មានកំណែ grayscale-16x16-mean-cells-v2 ប្រើតម្លៃធំជាងរវាងភាពខុសគ្នានៃមធ្យម luma និងសមាមាត្រក្រឡា thumbnail ដែលភាពខុសគ្នាបន្ទាប់ពីការធ្វើឱ្យមានស្តង់ដាររបស់វាមានយ៉ាងហោចណាស់ 0.05។ កម្រិតកំណត់ស្ទួនគឺជាថេរ 0.04 ដែលត្រូវបានជ្រើសរើសដើម្បីភាពអាចទស្សន៍ទាយបាន ជាជាងដាក់បង្ហាញជាការកំណត់នៅពេលដំណើរការ។ សញ្ញាកម្រិតពណ៌ខ្ពស់បន្ទាប់បន្សំនេះរក្សាចលនាតូចៗ និងការផ្លាស់ប្តូរអត្ថបទដែលមើលឃើញ ដែលការប្រៀបធៀបផ្អែកតែលើមធ្យមអាចលាក់បាំងបាន។ កំហុស comparator ឬ decoder បរាជ័យដោយបើកចំហ និងរក្សាការគ្របដណ្តប់។ metadata លទ្ធផលបំបែកបេក្ខភាពដែលបានស្រង់ ស៊ុមដែលបានប្រើដោយជោគជ័យ និងស្ទួនរូបភាពដែលបានដកចេញ។

ផ្នែកវីដេអូដែលបានសម្គាល់យ៉ាងច្បាស់អាចស្នើសុំសន្លឹករូបភាពទំនាក់ទំនងដែលមានសញ្ញាពេលវេលា។ bridge បង្កើតក្រឡាចត្រង្គ JPEG ដែលមានច្រើនបំផុត 4 ជួរឈរ និង 16 ស៊ុម។ ក្រឡា 512-pixel នីមួយៗបញ្ចូលសញ្ញាពេលវេលានៃប្រភពរបស់វាទៅក្នុងបន្ទះខាងក្រោមដែលមានកម្រិតពណ៌ខ្ពស់ ខណៈសញ្ញាពេលវេលាដូចគ្នានោះនៅតែមានក្នុង metadata ជាអត្ថបទ សម្រាប់ការភ្ជាប់ទំនាក់ទំនង និងសវនកម្មនៅដំណាក់កាលបន្ទាប់។ JPEG ពេញលេញនៅតែត្រូវបានកំណត់ត្រឹម 32 MiB។ ប្រសិនបើ sharp មិនអាចឌិកូដ ឬរៀបបញ្ចូលក្រឡាចត្រង្គបាន bridge នឹងត្រឡប់ទៅប្រើស៊ុម JPEG ដាច់ដោយឡែកវិញ។ ការបោះបង់ពី client នៅតែបន្តឆ្លងកាត់ប្រតិបត្តិការសន្លឹកនេះ។

ភស្តុតាងសម្រាប់ការដំឡើងទៅប្រើប្រាស់ត្រូវបានបំបែកដោយចេតនាពី microbenchmark នៃការរៀបបញ្ចូលសិប្បនិម្មិត។ scripts/perf/video-bridge-contact-sheet-eval.ts កំណត់ harness A/B ដែលមាន schema ជាកំណែ សម្រាប់គំរូ vision ដែលអាចប្រើជាមួយ OpenAI ពិតប្រាកដ។ វាវាស់ tokens ដែល provider បានរាយការណ៍ រយៈពេលពន្យារពីដើមដល់ចប់ (រួមទាំងការរៀបបញ្ចូលសន្លឹក) ចំនួនការហៅគំរូ និងការរក្សាទុកព័ត៌មានពិតដែលកំណត់ដោយ manifest។ ការឆ្លើយតបដើមរបស់គំរូមិនត្រូវបានសរសេរទៅក្នុងរបាយការណ៍ទេ។ មានតែសេចក្ដីសង្ខេប SHA-256 និង IDs នៃព័ត៌មានពិតដែលត្រូវគ្នាប៉ុណ្ណោះដែលត្រូវបានរក្សាទុក។ harness មិនធ្វើការហៅបណ្ដាញ ឬគំរូបង់ប្រាក់ទេ លុះត្រាតែបានផ្ដល់ --execute-real ហើយបានកំណត់រចនាសម្ព័ន្ធ --model, OMNIROUTE_BASE_URL និង OMNIROUTE_API_KEY។ បើគ្មានការដំណើរការពិតដែលបានបញ្ជាក់ច្បាស់នោះ សាលក្រមដែលម៉ាស៊ីនអាចអានបានរបស់វានៅតែជា HOLD។ ការវាស់វែង payload/ចំនួនការហៅសិប្បនិម្មិតតែឯង មិនមែនជាភស្តុតាងសម្រាប់ការដំឡើងទៅប្រើប្រាស់ទេ។

អ្នកហៅអាចភ្ជាប់ array transcript.cues ជាជម្រើសទៅនឹងផ្នែកវីដេអូដែលគាំទ្រ នៅពេលពួកគេមានអត្ថបទដែលបានតម្រឹមរួចហើយ។ cue នីមួយៗត្រូវតែមាន text ចន្លោះ start/end មានកំណត់ដែលស្ថិតក្នុងរយៈពេលដែលបានស្ទង់ និង source ដែលស្ថិតក្នុងបញ្ជីអនុញ្ញាត (client, embeddedaudio-bridge)។ confidence មានតម្លៃលំនាំដើមជា 1 ហើយត្រូវស្ថិតនៅចន្លោះ 0 និង 1។ cues ដែលស្ទួនគ្នាពិតប្រាកដត្រូវបានបង្រួមជាមួយគ្នា។ OmniRoute មិនដែលចាប់ផ្ដើមការចម្លងសំឡេងជាអត្ថបទពី metadata នេះទេ៖ cues ដែលបានផ្ទៀងផ្ទាត់ត្រូវបានចម្លងទៅក្នុងលទ្ធផលដែលបានពិពណ៌នា ជាមួយប្រភព កម្រិតទំនុកចិត្ត និងចន្លោះពេល ហើយត្រូវបានបង្ហាញជាការសង្កេតដែលមិនអាចទុកចិត្តបាន អមជាមួយចំណងជើងរូបភាពនៃស៊ុម។ អត្ថបទមិនត្រឹមត្រូវ ក្រៅដែន ឬគ្មានប្រភពច្បាស់លាស់ ត្រូវបានបដិសេធ ជាជាងលាយបញ្ចូលទៅក្នុងស្ទ្រីមចំណងជើងរូបភាព។ បច្ចុប្បន្ន field source ត្រូវបានប្រកាសដោយអ្នកហៅ មិនមែនផ្ទៀងផ្ទាត់ដោយ server ទេ៖ OmniRoute អនុវត្តឱ្យតម្លៃនេះត្រូវតែជាខ្សែអក្សរមួយក្នុងចំណោមខ្សែអក្សរដែលបានអនុញ្ញាតទាំងបី ប៉ុន្តែមិនទាន់បញ្ជាក់តាមគ្រីបថាស្លាក embeddedaudio-bridge ពិតជាបានមកពីការស្រង់ដែលគ្រប់គ្រងដោយ server នោះទេ។ សូមចាត់ទុក source ជាតម្រុយដែលមិនអាចទុកចិត្តបាន រហូតដល់ការផ្ទៀងផ្ទាត់នោះត្រូវបានដាក់ឱ្យប្រើប្រាស់។ កុំបង្កើតការសម្រេចចិត្តផ្ដល់សិទ្ធិដោយផ្អែកលើវា។

អ្នកហៅប្រើកម្រិតខ្ពស់អាចផ្តល់ track audioTranscript ដែលបានអនុញ្ញាតរួចហើយ សម្រាប់វីដេអូដូចគ្នា។ ចំណុចតភ្ជាប់នៃការបញ្ចូលគ្នាដំណើរការការសង្កេតផ្នែករូបភាព និងសំឡេងក្រោម កាលកំណត់ និងសញ្ញាបោះបង់តែមួយ រៀបលំដាប់ពួកវាលើបន្ទាត់ពេលវេលារួម បង្រួម ធាតុស្ទួនដូចគ្នាបេះបិទ និងរាយការណ៍លទ្ធផលមួយផ្នែក នៅពេលមានតែផ្នែកម្ខាងជោគជ័យ។ audioTranscript ដែលមិនត្រឹមត្រូវនឹងបន្ថយទៅជាលទ្ធផលមួយផ្នែកនោះ — ការពិពណ៌នា ផ្នែករូបភាពត្រូវបានរក្សាទុក ហើយសាខាសំឡេងកត់ត្រាកូដបរាជ័យដែលបានសម្អាត — ជំនួសឱ្យការធ្វើឱ្យវីដេអូទាំងមូលបរាជ័យ។ ភាពអាចប្រើបានតាមសាខានីមួយៗ ទង់សម្គាល់លទ្ធផលមួយផ្នែក និងកូដបរាជ័យដែលបានសម្អាត ត្រូវបានរក្សាទុកនៅក្នុងលទ្ធផលដែលបានពិពណ៌នា នៅក្នុង មេតាទិន្នន័យ guardrail (audioFusionRuns/audioFusionPartials/ audioFusionFailureCodes) នៅក្នុងមេតាទិន្នន័យឃ្លាំងសម្ងាត់លទ្ធផល និងនៅក្នុងកម្មវិធីរាប់ ការបញ្ចូលគ្នារបស់ bridge។ ផ្លូវ Video Bridge លំនាំដើមមិនហៅការបម្លែងសំឡេងទៅជាអត្ថបទ ឬទាញយកច្បាប់ចម្លងមេឌៀទីពីរទេ។ បើគ្មាន track ដែលបានបញ្ជាក់យ៉ាងច្បាស់នោះទេ វានៅតែ ដំណើរការតែវីដេអូប៉ុណ្ណោះ។

ការរក្សាទុកប្រតិចារិក (#12150 P1)។ វាអនុវត្តដោយស្វ័យប្រវត្តិរាល់ពេលដែល Video Bridge (ដែលត្រូវជ្រើសបើកដោយខ្លួនវា) បង្ហាញ cue នៃប្រតិចារិក — មិនមាន ទង់សម្គាល់ការរក្សាទុកដាច់ដោយឡែកទេ។ នៅពេលសំណើមួយបង្ហាញ cue នៃប្រតិចារិកណាមួយ (ជា transcript ដែលប្រកាសដោយអ្នកហៅ ឬ audioTranscript ដែលបានបញ្ចូលគ្នា) guardrail សម្គាល់វាជា videoBridgeObserved ហើយបង្កើតច្បាប់ចម្លងលាក់ព័ត៌មាននៃការពិពណ៌នាវីដេអូ — ជាការបង្ហាញដូចគ្នាបេះបិទ ដែលខ្លឹមសារអត្ថបទសេរីរបស់ cue នីមួយៗត្រូវបានជំនួសដោយ [redacted-video-transcript] ដែលបង្កើតឡើងដោយជំនួស field cue ដែលមានរចនាសម្ព័ន្ធ មុនពេលបង្កើត string (មិនដែលធ្វើដោយញែកអត្ថបទដែលបានធ្វើឱ្យរាបស្មើទេ ដូច្នេះគ្មានខ្លឹមសារ cue ណាមួយ — ទោះជាបង្កគ្រោះថ្នាក់ ឬធម្មតា រួមទាំងខ្លឹមសារដែលមាន ] ដូចជា [inaudible]/[music] — អាចនៅសេសសល់បានឡើយ)។ ខ្លឹមសារសំណើក្នុងកំណត់ហេតុការហៅដែលបានរក្សាទុក ប្តូរផ្នែកអត្ថបទនីមួយៗដែលបានមកពីវីដេអូដោយច្បាប់ចម្លងលាក់ព័ត៌មាននោះ ដោយផ្គូផ្គងតាមភាពស្មើគ្នា នៃខ្លឹមសារ។ ចំណុចយោង fullText ត្រូវបានអានឡើងវិញពី payload របស់ guardrail មុនការហៅ ដែលបានបញ្ចប់ ដូច្នេះការផ្គូផ្គងនៅតែជោគជ័យ បន្ទាប់ពី guardrail បន្តបន្ទាប់នៅពេលក្រោយ (កម្មវិធី បិទបាំង PII និងព័ត៌មានសម្ងាត់ ដែលមានអាទិភាព 10/95) កែសរសេរអត្ថបទពិពណ៌នានៅនឹងកន្លែង និង បន្ទាប់ពីការបញ្ចូល system-prompt/handoff/memory រៀបចំអារេ message ឡើងវិញ។ ខ្លឹមសារ ដែលបានផ្ញើទៅកាន់ model ខាងលើមិនត្រូវបានផ្លាស់ប្តូរទេ។ សំណើដែលបានសង្កេតក៏មិនបញ្ចូល Memory អចិន្ត្រៃយ៍ណាមួយដែរ (ការស្រង់ចេញដែលបានមកពីទាំងសំណើ និងការឆ្លើយតបត្រូវបានរំលង) ដូច្នេះចម្លើយផ្ទាល់របស់ model មិនអាចបន្ទរអត្ថបទប្រតិចារិកចូលទៅក្នុង Memory បានទេ។

ផ្ទៃរក្សាទុកដែលនៅតែបើក និងត្រូវបានតាមដានសម្រាប់ការងារបន្ត (P2, #12430)៖ snapshot សំណើរបស់ client ឆៅ មុន guardrail នៅក្នុង artifact កំណត់ហេតុលម្អិត; previous_response_id continuation fail-closed; internal dispatch នៃ derived-prompt ដែលបង្កប់ប្រតិចារិកនៅក្នុង string prompt ដែលបានសំយោគ (ដំណាក់កាល pipeline, context-handoff); និងខ្លឹមសារឆ្លើយតប / ច្បាប់ចម្លង semantic-cache នៃចម្លើយរបស់ model ដែលដកស្រង់ប្រតិចារិក។ ទាំងនេះគឺជាផ្ទៃប្រភេទ raw/response ឬ opt-in ដែលស្ថិតនៅក្រៅវិសាលភាព persisted-request-body + Memory របស់ P1។

វដ្តជីវិតខាងក្នុង /api/modality-bridge/video/drilldown គឺជាស្រទាប់ឃ្លាំងសម្ងាត់ដាច់ដោយឡែក ដែលបានផ្ទៀងផ្ទាត់តាម loopback/token។ ប្រតិបត្តិការនីមួយៗក៏តម្រូវឱ្យមាន ID principal ស្រអាប់ canonical មួយផងដែរ។ មុនពេលអ្នកហៅក្នុង production ត្រូវបានអនុញ្ញាត វាត្រូវ ទាញយក ID នោះពី tenant ដែលបានផ្ទៀងផ្ទាត់ ហើយមិនត្រូវបញ្ជូនតម្លៃដែលបានជ្រើសដោយ client ឡើយ។ key របស់ឃ្លាំងសម្ងាត់ភ្ជាប់ principal នោះទៅនឹង ID session និង video-reference canonical ដោយរក្សាទុកតែ key ដែលបានទាញយកពី SHA-256 របស់ពួកវា និង កំណត់វិសាលភាពទាំងការអាន និងការលុបឱ្យស្ថិតក្រោម principal ដូចគ្នា។ ឃ្លាំងសម្ងាត់រក្សាទុក frame JPEG ដែលបានបង្កើតមិនលើសពី 16 ក្នុងមួយ entry ធ្វើឱ្យពួកវាផុតកំណត់បន្ទាប់ពីដប់នាទី និងគាំទ្រ ការអាន start/end ដែលមានដែនកំណត់ ឬការលុប session ដោយច្បាស់លាស់។

principal នីមួយៗត្រូវបានកំណត់ត្រឹម 16 entries និងទិន្នន័យ JPEG canonical ចំនួន 64 MiB។ ដែនកំណត់ ទាំងនោះឯករាជ្យពីពិដានសកល 64-entry/256 MiB៖ សម្ពាធកូតារបស់ principal បណ្តេញចេញតែ entries ដែលត្រូវបានប្រើថ្មីៗតិចបំផុតរបស់ principal នោះប៉ុណ្ណោះ មុនពេលពិចារណា ការបណ្តេញចេញតាម LRU សកល។ entries ដែលផុតកំណត់ត្រូវបានសម្អាតចេញពីទាំងការគណនារបស់ principal និង សកល នៅពេលមានសកម្មភាពឃ្លាំងសម្ងាត់ ខណៈការបោះបង់ និងការបរាជ័យនៃការផ្ទៀងផ្ទាត់មិន commit ការជំនួសមួយផ្នែកទេ។

ឃ្លាំងសម្ងាត់បដិសេធ Base64 ដែលមិនមែនជា canonical, padding លើស, មេឌៀដែលមិនមែនជា JPEG, JPEG ដែលខូចទ្រង់ទ្រាយ ឬ ត្រូវបានកាត់ខ្លី និង JPEG ដែលបង្កើតការព្រមានក្នុងអំឡុងពេល decode រូបភាពពេញលេញដោយ sharp ដែលមានដែនកំណត់។ វា encode រូបភាពដែលបានទទួលយកនីមួយៗឡើងវិញជា JPEG canonical ទាញយក width និង height ពី bytes ដែលបាន decode ជំនួសឱ្យការជឿទុកចិត្តលើ fields របស់អ្នកហៅ និងបោះបង់ polyglot bytes ដែលភ្ជាប់នៅខាងចុង ជំនួសឱ្យការរក្សាទុកពួកវា។ មានតែ buffer បង្ហាប់ canonical ដែលមានដែនកំណត់ប៉ុណ្ណោះដែលត្រូវបានគិតបញ្ចូលក្នុងកូតាទាំងពីរ។ ដែនកំណត់ JSON តាមការបញ្ជូនរួមបញ្ចូល overhead របស់ Base64 សម្រាប់ពិដាន decoded-input ទំហំ 32 MiB។ រាល់ derivation ដែលបានរក្សាទុក កត់ត្រាទ្រង់ទ្រាយ/គុណភាពបង្ហាញ JPEG ដែលបានផ្ទៀងផ្ទាត់ គោលការណ៍ sampling, កំណែ derivation ពេលវេលាបង្កើត content hash ដែលគណនាដោយ server និង parent reference ដែលបាន hash ព្រមទាំង parent-content hash របស់អ្នកហៅដែលអាចទុកចិត្តបាន។ ការបោះបង់ត្រូវបានពិនិត្យ នៅចន្លោះដំណាក់កាល decode/hash អសមកាល មុនពេល atomic cache commit។

ផ្នែកការងារនេះមិនទាន់ភ្ជាប់ producer ក្នុង production ទៅកាន់ route និងមិន ផ្តល់ការជ្រើស variant ពហុ-resolution នៅឡើយទេ។ ដូច្នេះផ្លូវសំណើ Video Bridge ដែលមានតម្លាភាព មិនបង្កការងារបន្ថែមទេ ខណៈការទាញយក principal ដែលភ្ជាប់ជាមួយ tenant និង វដ្តជីវិតពហុ-resolution FU-08 ពេញលេញ នៅតែជាការងារបន្តដែលបានកំណត់ច្បាស់លាស់ ជាជាង ត្រូវបានចងក្រងជាឯកសារថាជាឥរិយាបថដែលបានបញ្ចប់។

ស៊ុមត្រូវបានដាក់ចំណងជើងតាមលំដាប់លំដោយដោយប្រើម៉ូដែល Video ដែលបានកំណត់រចនាសម្ព័ន្ធ។ ការកំណត់ជំនួស Video ទទេ នឹងទទួលការកំណត់ Vision បន្ត; ប្រសិនបើទាំងពីរទទេ នោះកម្មវិធីកំណត់ផ្លូវស្វ័យប្រវត្តិរបស់ Vision នឹងជ្រើសរើសម៉ូដែលមានសមត្ថភាពមើលឃើញដែលមានប្រសិទ្ធភាព។ ចំណងជើងដែលបានបង្កើតដោយជោគជ័យ ជំនួសផ្នែកដើមដោយបុព្វបទថេរ [Video description: ដែលក៏ សម្គាល់អត្ថបទថាជាការសង្កេតដែលទាញយកពីមេឌៀមិនគួរឱ្យទុកចិត្ត និងប្រាប់ម៉ូដែលបន្តបន្ទាប់ មិនឱ្យធ្វើតាមការណែនាំដែលបានរកឃើញនៅក្នុងមេឌៀ។ សោឃ្លាំងសម្ងាត់ចំណងជើងស៊ុម រួមមានបៃ JPEG, prompt, timestamp និងម៉ូដែលមានប្រសិទ្ធភាព; មានតែ ចំណងជើងដែលបានបង្កើតដោយជោគជ័យប៉ុណ្ណោះដែលត្រូវបានរក្សាទុកក្នុងឃ្លាំងសម្ងាត់។ ធាតុក្នុងឃ្លាំងសម្ងាត់រក្សាទុកម៉ូដែលផលិតករដែលទទួលបានជោគជ័យពិតប្រាកដ រួមទាំងម៉ូដែលបម្រុង; bridge រាយការណ៍ mixed នៅពេលស៊ុមផ្សេងៗគ្នា ត្រូវបានបង្កើតដោយម៉ូដែលផ្សេងៗគ្នា។ ការប្រើទិន្នន័យពីឃ្លាំងសម្ងាត់ឡើងវិញនឹងប្រើអត្តសញ្ញាណផលិតករនោះ ជំនួសឱ្យការដាក់ស្លាកវាឡើងវិញថាជាផែនការកំណត់ផ្លូវដែលបានស្នើ។ ឃ្លាំងសម្ងាត់លទ្ធផលវីដេអូទាំងមូល ត្រូវបានបង្កើតសោផ្អែកលើគ្រប់ទិន្នន័យបញ្ចូលដែលផ្លាស់ប្តូរលទ្ធផល — prompt, ម៉ូដែលមានប្រសិទ្ធភាព, គោលការណ៍សំណាក, ចំនួនស៊ុម, របៀបវិភាគតាមន័យ, fingerprint SHA-256 នៃព័ត៌មានជំនួយផ្តោតដែលបានធ្វើឱ្យមានស្តង់ដារ, focus window, transcript, audioTranscript និងទង់ contact-sheet — ដូច្នេះការផ្លាស់ប្តូរវិមាត្រណាមួយក្នុងចំណោមនោះ គឺជាការមិនត្រូវនឹងឃ្លាំងសម្ងាត់ មិនមែនជាការប្រើទិន្នន័យចាស់ឡើងវិញនោះទេ។ កំណែគោលការណ៍លុបស្ទួនរូបភាព, កម្រិតចាប់ផ្តើម និងចំនួនស៊ុមបេក្ខភាពដែលបានកំណត់ព្រំដែន ក៏ត្រូវបានបញ្ជាក់យ៉ាងច្បាស់នៅក្នុង សោ និង metadata របស់ឃ្លាំងសម្ងាត់លទ្ធផលផងដែរ; ដូច្នេះ ការផ្លាស់ប្តូរគោលការណ៍មិនអាចប្រើការពិពណ៌នាវីដេអូទាំងមូល ដែលចាស់ឡើងវិញបានទេ។ metadata របស់ឃ្លាំងសម្ងាត់លទ្ធផល v4 រក្សាទុករបៀប និង fingerprint ប៉ុន្តែមិនរក្សាទុកភារកិច្ចឆៅរបស់អ្នកប្រើឡើយ។ metadata របស់ guardrail រាយការណ៍ទាំង របៀបវិភាគដែលបានស្នើ និងរបៀបមានប្រសិទ្ធភាព; របៀប focused ដែលបានស្នើដោយគ្មាន អត្ថបទអ្នកប្រើដែលអាចប្រើបាន នឹងត្រូវបានរាយការណ៍ថាមានប្រសិទ្ធភាពជា full

guardrail ស្រង់ចេញគ្រប់ផ្នែកវីដេអូដែលបានគាំទ្រ ប៉ុន្តែពិពណ៌នាមិនលើសពី modalityBridgeVideoMaxVideos ទេ។ សម្រាប់គោលដៅដែលត្រូវបានបញ្ជាក់ថាមាន supportsVideo === false វីដេអូដែលបរាជ័យ និងលើសកម្រិត នឹងក្លាយជាសញ្ញាសម្គាល់អត្ថបទសុវត្ថិភាពយ៉ាងច្បាស់ ដើម្បីកុំឱ្យវីដេអូឆៅណាមួយនៅសល់។ នៅពេលមិនដឹងសមត្ថភាព ផ្នែកទាំងនោះ នៅតែមិនត្រូវបានប៉ះពាល់។ គោលដៅដែលមាន supportsVideo === true នឹងរំលង bridge។ សញ្ញាបញ្ឈប់សំណើរបស់ client ត្រូវបានបញ្ជូនបន្តតាមរយៈការទាញយក, ជួរ broker, subprocess និងការហៅបង្កើតចំណងជើង; ការបញ្ឈប់នឹងឈប់នៅចន្លោះវីដេអូ ហើយមិនដែលបើកផ្លូវ ទៅកាន់មេឌៀឆៅនៅពេលបរាជ័យឡើយ។

ការកំណត់ពេលដំណើរការត្រូវបានរក្សាទុកក្នុង DB និងផ្ទៀងផ្ទាត់ដោយ Zod៖

សោ លំនាំដើម ជួរ / ឥរិយាបថ
modalityBridgeVideoEnabled false ពេលដំណើរការជាជម្រើស ដែលត្រូវបើកប្រើដោយចេតនា
modalityBridgeVideoAnalysisMode "full" full រក្សាចំណងជើងទូទៅ; focused ប្រើបរិបទអ្នកប្រើចុងក្រោយដែលមានព្រំដែន និងមិនគួរឱ្យទុកចិត្ត
modalityBridgeVideoModel "" ទទួលម៉ូដែល Vision Bridge បន្ត
modalityBridgeVideoFrameCount 8 116
modalityBridgeVideoSamplingPolicy "uniform" uniform, scene_awaresegment_aware តាមសមាមាត្រ; ការបរាជ័យរបស់ឧបករណ៍រកឃើញនឹងត្រឡប់ទៅ uniform
modalityBridgeVideoMaxVideos 1 14
modalityBridgeVideoTimeout 120000 1000120000 ms

តម្លៃ timeout របស់ Video ដែលបានរក្សាទុកពីប្រព័ន្ធចាស់ និងលើសពី 120 វិនាទី ត្រូវបានកម្រិតត្រឹម ថ្ងៃកំណត់របស់ broker; ការសរសេរការកំណត់ថ្មីដែលលើសពីដែនកំណត់នោះ នឹងត្រូវបានបដិសេធ។ GET /api/modality-bridge/video/runtime ទាមទារទីតាំង loopback ដែលបានបោះត្រាទុកចិត្ត មុនពេលការផ្ទៀងផ្ទាត់អត្តសញ្ញាណ ឬការស្ទង់ពេលដំណើរការ បន្ទាប់មកទាមទារ auth សម្រាប់ការគ្រប់គ្រង។ វាត្រឡប់តែ available, កំណែ FFmpeg/ffprobe ដែលបានសម្អាត និងហេតុផលថេរ នៅពេល runtime មិនអាចប្រើបាន។ endpoint ស្រង់ចេញខាងក្នុងមិនមែនជា API ផ្ទុកឡើងសាធារណៈទេ៖ ការកកស្ទះជួរត្រឡប់ 503 រួមជាមួយ Retry-After, ការផ្តាច់របស់អ្នកហៅ ត្រឡប់ 499 ហើយថ្ងៃកំណត់ថេររបស់ broker ត្រឡប់ 504។ ការឆ្លើយតបដែលបានបម្លែងបន្ថែម video->text;model=<visionModel>;parts=<videos> ទៅក្នុង header កណ្តាល x-omniroute-modality-bridge ដោយមិនដកផ្នែក Vision ឬ Audio ចេញ។

កម្មវិធីបិទបាំង PII (piiMasker.ts)

ដំណើរការលើដំណាក់កាល ទាំងពីរ

  • preCall ក្លូន payload, ឆ្លងកាត់ system, messages, input និង prompt (រួមទាំងធាតុ plain string) ហើយអនុវត្ត processPII() (ពី @/shared/utils/inputSanitizer) ទៅលើវាល string content/text។ នៅពេល PII_REDACTION_ENABLED=true PII ដែលបានរកឃើញត្រូវបានលាក់នៅក្នុង payload ដែលផ្ញើចេញ។ វាមិនអាស្រ័យលើ INPUT_SANITIZER_MODE ទេ (ដែលគ្រប់គ្រងតែ គោលការណ៍ prompt-injection ប៉ុណ្ណោះ)។ នៅពេលការលាក់ត្រូវបានបិទ ការហៅនឹងកត់ត្រា ចំនួននៃការរកឃើញដោយមិនសរសេរខ្លឹមសារឡើងវិញ។
  • postCall ធ្វើ deep-clone លើការឆ្លើយតប, ដំណើរការ sanitizePIIResponse() រួមជាមួយ កម្មវិធីបិទបាំងទម្រង់ Responses-API (maskResponsesOutput — គ្របដណ្តប់ output_text និង output[].content[].text)។ ប្រសិនបើមានការលាក់ណាមួយកើតឡើង ការឆ្លើយតបដែលបានកែប្រែនឹងជំនួសការឆ្លើយតបដើម។

guardrail មិនដែលទប់ស្កាត់ទេ; វាគ្រាន់តែបន្ថែមចំណារពន្យល់ (meta.detections, meta.redacted) ឬសរសេរឡើងវិញប៉ុណ្ណោះ។

ការចាក់បញ្ចូល Prompt (promptInjection.ts)

រកឃើញរចនាសម្ព័ន្ធបង្កគ្រោះថ្នាក់នៅក្នុងខ្លឹមសារដែលអ្នកប្រើបានផ្តល់ និងអនុវត្ត គោលការណ៍ដែលបានកំណត់រចនាសម្ព័ន្ធ។ ឥរិយាបថត្រូវបានកំណត់ដោយអថេរបរិស្ថាន និងជម្រើស constructor៖

ការកំណត់ អថេរបរិស្ថាន លំនាំដើម ឥទ្ធិពល
បើកដំណើរការ INPUT_SANITIZER_ENABLED true នៅពេលជា false guardrail នឹងបញ្ចប់ដំណើរការភ្លាមៗ។
របៀប INJECTION_GUARD_MODE / INPUT_SANITIZER_MODE warn គោលការណ៍ការពារ injection៖ block, warnlog។ (redact ត្រូវបានទទួលយកសម្រាប់ភាពឆបគ្នាថយក្រោយ ប៉ុន្តែវា មិន លុបអត្ថបទ injection ទេ។ ការសរសេរ PII ក្នុងសំណើឡើងវិញត្រូវបានគ្រប់គ្រងដោយ PII_REDACTION_ENABLED។)
កម្រិតទប់ស្កាត់ ជម្រើស blockThreshold / INPUT_SANITIZER_BLOCK_THRESHOLD (ឈ្មោះក្លែងក្លាយ INJECTION_GUARD_BLOCK_THRESHOLD) high កម្រិតធ្ងន់ធ្ងរអប្បបរមាដែលតម្រូវឱ្យមានដើម្បីទប់ស្កាត់។ តាមលំនាំដើម កម្រិតមធ្យមគឺសម្រាប់តែតាមដានប៉ុណ្ណោះ។

លំដាប់អាទិភាពនៃរបៀប (getMode)៖ options.mode របស់អ្នកហៅ → ការកំណត់ជំនួសដោយ feature flag របស់ DB សម្រាប់ INJECTION_GUARD_MODE (Dashboard → Settings → Feature Flags) → env INJECTION_GUARD_MODE → env INPUT_SANITIZER_MODEwarn។ ដូច្នេះ ការកំណត់ជំនួសពី dashboard មានអាទិភាពលើអថេរ env ដែលអនុញ្ញាតឱ្យ UI នៃ Feature Flags គ្រប់គ្រង guard ដែលកំពុងដំណើរការភ្លាមៗ (មិនចាំបាច់ចាប់ផ្ដើមឡើងវិញ)។ ការអានពី DB មានយន្តការសុវត្ថិភាពពេលបរាជ័យ៖ ប្រសិនបើវាមានកំហុស guard នឹងត្រឡប់ទៅប្រើឥរិយាបថផ្អែកលើ env ហើយនៅពេលគ្មាន ការកំណត់ជំនួស ឥរិយាបថនឹងដូចគ្នាបេះបិទនឹងការកំណត់តាម env តែប៉ុណ្ណោះ។

ប្រភពនៃការរកឃើញ៖

  1. sanitizeRequest() ពី @/shared/utils/inputSanitizer (សំណុំឧបករណ៍រកឃើញរួម ដែលត្រូវបានប្រើនៅកន្លែងផ្សេងទៀតក្នុង pipeline)។
  2. DEFAULT_GUARD_PATTERNS ដែលមានស្រាប់ (បច្ចុប្បន្នមាន system_override_inline និង markdown_system_block ដែលទាំងពីរមានកម្រិតធ្ងន់ធ្ងរ high)។
  3. customPatterns ជាជម្រើស ដែលត្រូវបានបញ្ជូនតាមជម្រើស constructor (string, regex ឬ record { name, pattern, severity })។

នៅពេល mode === "block" ហើយ មានការរកឃើញយ៉ាងហោចណាស់មួយដែលឈានដល់កម្រិត ធ្ងន់ធ្ងរដែលបានកំណត់ preCall នឹងត្រឡប់ { block: true, message: "Request rejected: suspicious content detected" }។ នៅក្នុងរបៀប warn/log guardrail នឹងកត់ត្រា log ប៉ុន្តែ អនុញ្ញាតឱ្យមានការហៅ។ helper រួម evaluatePromptInjection() ក៏ត្រូវបាន export ផងដែរ សម្រាប់អ្នកហៅដែលត្រូវការវាយតម្លៃ prompt ដោយមិនឆ្លងកាត់ registry។

ដែនកំណត់នៃការស្កេន (v3.8.20)៖ ឧបករណ៍រកឃើញត្រួតពិនិត្យតែ 16 KB ដំបូង នៃ អត្ថបទ prompt ដែលបានភ្ជាប់ — MAX_INJECTION_SCAN_BYTES = 16 * 1024 (16 384 bytes) នៅក្នុង src/shared/utils/inputSanitizer.ts។ ទាំង detectInjection() និង evaluatePromptInjection() អនុវត្ត slice(0, MAX_INJECTION_SCAN_BYTES) មុនពេលដំណើរការ pattern loop។ សេចក្ដីបង្គាប់ injection ស្ថិតនៅជិតផ្នែកខាងលើនៃ input ដូច្នេះវាកំណត់ការប្រើប្រាស់ CPU/GC របស់ regex លើ payload ដែលមានទំហំច្រើនរយ KB ដោយមិនធ្វើឱ្យសមត្ថភាពរកឃើញចុះខ្សោយទេ (សូមមើល #3932, #4041)។

ឧបករណ៍បិទបាំងព័ត៌មានសម្ងាត់ (credentialMasker.ts)

ដំណើរការនៅលើដំណាក់កាល ទាំងពីរ និងនៅចុងក្រោយក្នុង chain លំនាំដើម (អាទិភាព 95)។ វាលាក់ លំនាំ API key / secret token ដែលគេស្គាល់ច្បាស់ពី payload ចេញក្រៅ (ខ្លឹមសារ សារ, argument របស់ tool call និងលទ្ធផលរបស់ tool) ព្រមទាំង response របស់ provider ដើម្បីកុំឱ្យ ព័ត៌មានសម្ងាត់ដែលបានបិទភ្ជាប់ក្នុង prompt (ឬត្រូវបានបង្ហាញឡើងវិញដោយលទ្ធផលរបស់ tool) លេចធ្លាយ ទៅកាន់ provider ខាងលើ ឬត្រឡប់ទៅ client វិញ។

  • បើកប្រើតាមការជ្រើសរើសតែប៉ុណ្ណោះ ដោយប្រើអនុសញ្ញាដូចគ្នានឹងការលាក់ PII (ជិតស្និទ្ធនឹង Hard Rule #20)៖ ត្រូវបានបិទ លុះត្រាតែ settings.credentialRedactionEnabled === true CREDENTIAL_REDACTION_ENABLED=true។ នៅពេលបិទ guardrail នឹងមិនធ្វើអ្វីទាំងអស់ — វាមិនដែលទប់ស្កាត់ និងមិនដែលសរសេរឡើងវិញទេ។
  • redactCredentials() ឆ្លងកាត់ payload/response tree ទាំងមូល (walkValue(), មានសុវត្ថិភាពពី prototype pollution និងមានសុវត្ថិភាពពី cycle តាមរយៈ WeakSet) ហើយជំនួសការផ្គូផ្គងដោយ placeholder [REDACTED:<type>] ដោយ clone តែ branch ដែលពិតជា បានផ្លាស់ប្ដូរប៉ុណ្ណោះ។
  • CREDENTIAL_PATTERNS គ្របដណ្ដប់លើ key របស់ LLM provider (OpenAI, OpenAI-proj, Anthropic, Google, Hugging Face, Replicate), token របស់ VCS/SaaS (GitHub, Slack, Linear, Notion, npm, Postman, Discord), key សម្រាប់ការទូទាត់ (Stripe, Square), key របស់ cloud (AWS access key, Twilio, SendGrid, Mailgun), private key / JWT, connection string ដែលមានព័ត៌មានសម្ងាត់ (mongodb://user:pass@... ជាដើម) និង លំនាំតម្លៃ header ទូទៅ Authorization/x-api-key/api-key/apikey។ key ដែលមានទម្រង់ជា header (authorization, x-api-key, api-key, apikey) ត្រូវបានលាក់តាមរចនាសម្ព័ន្ធ (តែតម្លៃប៉ុណ្ណោះ ដោយរក្សា prefix នៃ scheme ដូចជា Bearer /Basic ) ជាជាងតាមរយៈ text regex ទូទៅ។
  • guardrail មិនដែលទប់ស្កាត់ទេ។ វាគ្រាន់តែសរសេរឡើងវិញ (modifiedPayload / modifiedResponse) និងបន្ថែម annotation (meta.credentialsRedacted, meta.count)។

ការការពារកុំឱ្យមាន regression៖ tests/unit/credential-masker-guardrail.test.ts

កិច្ចសន្យាមូលដ្ឋាន (base.ts)

class BaseGuardrail {
  enabled: boolean;
  name: string;
  priority: number;

  constructor(name: string, options?: { enabled?: boolean; priority?: number });

  async preCall(payload: unknown, context: GuardrailContext): Promise<GuardrailResult | void>;

  async postCall(response: unknown, context: GuardrailContext): Promise<GuardrailResult | void>;
}

interface GuardrailResult<TValue = unknown> {
  block?: boolean; // true បញ្ឈប់ដំណើរការខ្សែសង្វាក់ភ្លាមៗ
  message?: string; // បង្ហាញនៅពេលទប់ស្កាត់
  meta?: Record<string, unknown> | null;
  modifiedPayload?: TValue; // ត្រូវបានត្រឡប់ដោយ preCall ដើម្បីសរសេរសំណើឡើងវិញ
  modifiedResponse?: TValue; // ត្រូវបានត្រឡប់ដោយ postCall ដើម្បីសរសេរការឆ្លើយតបឡើងវិញ
}

interface GuardrailContext {
  apiKeyInfo?: Record<string, unknown> | null;
  disabledGuardrails?: string[] | null;
  endpoint?: string | null;
  headers?: Headers | Record<string, unknown> | null;
  log?: GuardrailLog | Console | null;
  method?: string | null;
  model?: string | null;
  provider?: string | null;
  signal?: AbortSignal;
  sourceFormat?: string | null;
  stream?: boolean;
  targetFormat?: string | null;
}

Guardrail ផ្តល់សញ្ញាថា «គ្មានការផ្លាស់ប្តូរ» ដោយត្រឡប់ void, {}{ block: false }។ ការត្រឡប់ modifiedPayload/modifiedResponse នឹងជំនួស តម្លៃដែលហូរឆ្លងកាត់ខ្សែសង្វាក់សម្រាប់ guardrail បន្ទាប់ៗ។ signal?: AbortSignal នាំយកវដ្តជីវិតរបស់អ្នកហៅចូលទៅក្នុង guardrail។ ការបោះបង់សំណើគឺជាករណីលើកលែង fail-open ដោយចេតនា៖ ស្ពានមេឌៀនឹងបញ្ឈប់ការងារ និងសម្អាតដោយមិនស្ដារមេឌៀដើមទៅកាន់គោលដៅដែលដឹងថាមិនគាំទ្រវាឡើយ។

បញ្ជីចុះឈ្មោះ (registry.ts)

Singleton guardrailRegistry ផ្តល់ជូន៖

  • register(guardrail) — បន្ថែម guardrail មួយ (ឬជំនួសតាមឈ្មោះដែលបានធ្វើឱ្យមានទម្រង់ស្តង់ដារ) ហើយ តម្រៀបឡើងវិញតាម priority ពីតូចទៅធំ។
  • clear() / list() — មុខងារជំនួយផ្នែករដ្ឋបាល។
  • runPreCallHooks(payload, context) — ធ្វើដំណើរឆ្លងកាត់ guardrail ដែលសកម្ម បញ្ជូន payload តាមរយៈ modifiedPayload ហើយបញ្ឈប់នៅពេលជួប block: true ដំបូង។
  • runPostCallHooks(response, context) — ដំណើរការដូចគ្នានៅផ្នែក response។
  • resetGuardrailsForTests({ registerDefaults }) — សម្អាតស្ថានភាព និងអាច ចុះឈ្មោះតម្លៃលំនាំដើមឡើងវិញ ដើម្បីរក្សាភាពដាច់ដោយឡែកស្អាតសម្រាប់ការធ្វើតេស្ត។

Runner ទាំងពីរត្រឡប់ { blocked, payload|response, results, guardrail?, message? } ដែល results គឺជា array នៃ record GuardrailExecutionResult ដែលរួមមាន field blocked, skipped, modified, error និង meta សម្រាប់ guardrail នីមួយៗ ដែលមានប្រយោជន៍សម្រាប់ការតាមដាន។

ការបិទ Guardrail សម្រាប់សំណើនីមួយៗ

resolveDisabledGuardrails({ apiKeyInfo, body, headers }) ប្រមូលផ្ដុំបញ្ជី ឈ្មោះ guardrail ដែលបានដកធាតុស្ទួន ហើយគួរត្រូវបានរំលងសម្រាប់សំណើ បច្ចុប្បន្ន។ ប្រភព (ទាំងអស់ជាជម្រើស និងត្រូវបានបញ្ចូលគ្នាទាំងអស់)៖

  • apiKeyInfo.disabledGuardrails
  • disabledGuardrails ក្នុង body របស់សំណើ (កម្រិតកំពូល)
  • metadata.disabledGuardrails ក្នុង body របស់សំណើ
  • Header x-omniroute-disabled-guardrails (ឬឈ្មោះចាស់ x-disabled-guardrails)

តម្លៃអាចជា array នៃ string ឬ string ដែលបំបែកដោយសញ្ញាក្បៀស; ឈ្មោះត្រូវបាន បម្លែងឱ្យមានទម្រង់ស្តង់ដារជា kebab-case អក្សរតូច (pii_maskerpii-masker)។ លទ្ធផល ត្រូវបានបញ្ជូនតាមរយៈ context.disabledGuardrails ទៅ registry ដែលនឹងរំលង guardrail ដែលត្រូវគ្នា (skipped: true ក្នុង results)។

លំដាប់ប្រតិបត្តិការ

សម្រាប់សំណើនីមួយៗដែលឆ្លងកាត់ src/sse/handlers/chat.ts និង open-sse/handlers/chatCore.ts

  1. resolveDisabledGuardrails(...) បង្កើតបញ្ជីរំលងពី API key, body និង headers។
  2. guardrailRegistry.runPreCallHooks(body, ctx) ដំណើរការ guardrails តាមលំដាប់ priority ពីទាបទៅខ្ពស់៖
    • Guardrails ដែលត្រូវបានបិទនឹងត្រូវកត់ត្រាជា skipped
    • preCall របស់ guardrail នីមួយៗអាចសរសេរ payload ឡើងវិញតាមរយៈ modifiedPayload
    • block: true ដំបូងនឹងបញ្ឈប់ខ្សែដំណើរការភ្លាមៗ ហើយ handler នឹងត្រឡប់ response បដិសេធពី guardrail។
  3. Payload ដែលអាចត្រូវបានសរសេរឡើងវិញ នឹងបន្តទៅកាន់ combo routing និងការបញ្ជូន ទៅ upstream។
  4. បន្ទាប់ពី response ត្រូវបានរៀបចំរួច guardrailRegistry.runPostCallHooks(...) នឹងដំណើរការខ្សែដដែលលើ response។ block: true នៅទីនេះនឹងបោះបង់ response ពី upstream។

Guardrails ដែលបង្កើត exception នឹងត្រូវបានកត់ត្រាជាមួយ error: <message> និងកត់ត្រា log តាមរយៈ logger.warn ប៉ុន្តែខ្សែដំណើរការនៅតែបន្ត — នេះជាការរចនាបែប fail-open។

ការកំណត់រចនាសម្ព័ន្ធ

អថេរបរិស្ថានដែល guardrails មានស្រាប់អាន៖

អថេរ ប្រើដោយ ប្រសិទ្ធភាព
INPUT_SANITIZER_ENABLED prompt-injection កំណត់ជា false ដើម្បីបិទការរកឃើញទាំងស្រុង។
INPUT_SANITIZER_MODE prompt-injection គោលការណ៍ injection៖ warn, blocklog។ តម្លៃចាស់ redact មិនសរសេរអត្ថបទ injection ឡើងវិញទេ។
INJECTION_GUARD_MODE prompt-injection Mode សម្រាប់ injection guard; វាក៏ជា DB feature flag ដែល មានអាទិភាពលើ env vars ផងដែរ (DB > ENV)។
INPUT_SANITIZER_BLOCK_THRESHOLD prompt-injection កម្រិត severity អប្បបរមាដែល MODE=block បដិសេធ៖ high (លំនាំដើម), mediumlow
INJECTION_GUARD_BLOCK_THRESHOLD prompt-injection Alias ចាស់សម្រាប់ INPUT_SANITIZER_BLOCK_THRESHOLD
PII_REDACTION_ENABLED pii-masker នៅពេលជា true PII ក្នុង request នឹងត្រូវបានលាក់ (មិនអាស្រ័យលើ injection mode)។
PII_RESPONSE_SANITIZATION / _MODE pii-masker (downstream) គ្រប់គ្រងឥរិយាបថ masker នៅផ្នែក response។

Guardrails របស់ Modality Bridge អាន runtime config ពី settings store ដែលគាំទ្រដោយ DB (getSettings()), មិនមែនពី env vars ទេ។ Primary keys របស់ Vision គឺ modalityBridgeVisionEnabled, modalityBridgeVisionMode, modalityBridgeVisionModel, modalityBridgeVisionTaskAware, modalityBridgeVisionPrompt, modalityBridgeVisionTimeout, modalityBridgeVisionMaxImages, modalityBridgeVisionMaxChars, modalityBridgeCacheEnabled, modalityBridgeCacheTtlMinutes និង modalityBridgeCacheMaxEntries។ Keys ចាស់ visionBridge* ត្រូវបានទទួលយកត្រឹមតែជា fallback សម្រាប់ការអានមួយវដ្តដែលបានចងក្រងជាឯកសារ ប៉ុណ្ណោះ; ការសរសេរពី dashboard ប្រើ primary keys។ តម្លៃលំនាំដើម និង fallback resolver ស្ថិតនៅក្នុង src/shared/constants/modalityBridgeDefaults.ts ខណៈដែល constants ចាស់ត្រូវបានរក្សាទុកក្នុង src/shared/constants/visionBridgeDefaults.ts

Audio ប្រើ modalityBridgeAudioEnabled, modalityBridgeAudioModel, modalityBridgeAudioTimeout និង modalityBridgeAudioMaxClips រួមជាមួយ settings modalityBridgeCache* ដែលប្រើរួម។ Audio មិនមាន fallback សម្រាប់ keys ចាស់ទេ ព្រោះ keys ទាំងនេះត្រូវបានណែនាំជាមួយ schema របស់ Modality Bridge។

Video ប្រើ modalityBridgeVideoEnabled, modalityBridgeVideoAnalysisMode, modalityBridgeVideoModel, modalityBridgeVideoFrameCount, modalityBridgeVideoSamplingPolicy, modalityBridgeVideoMaxVideos និង modalityBridgeVideoTimeout រួមជាមួយ settings modalityBridgeCache* ដែលប្រើរួម។ វាត្រូវបានបិទតាមលំនាំដើម ព្រោះ FFmpeg/ffprobe ជា dependencies ប្រតិបត្តិការដែលអាចជ្រើសរើសបាន ហើយការបង្កើត caption សម្រាប់ frame បន្ថែម latency និងថ្លៃដើម model។

Guardrail ផ្ទាល់ខ្លួន

import { BaseGuardrail, guardrailRegistry } from "@/lib/guardrails";

class BudgetGuardrail extends BaseGuardrail {
  constructor() {
    super("budget", { priority: 50 });
  }

  async preCall(payload, ctx) {
    if (ctx.apiKeyInfo?.budgetExceeded) {
      return { block: true, message: "Daily budget exceeded" };
    }
    return { block: false };
  }
}

guardrailRegistry.register(new BudgetGuardrail());

ជំហាន៖

  1. បង្កើត src/lib/guardrails/myGuardrail.ts ដែលពង្រីកពី BaseGuardrail
  2. អនុវត្ត preCall និង/ឬ postCall
  3. ចុះឈ្មោះនៅពេល import (បញ្ចូលពី registerDefaultGuardrails) ឬ ហៅ guardrailRegistry.register(...) នៅពេល runtime — registry នឹងជំនួស guardrail មុនណាមួយដែលមានឈ្មោះបានធ្វើ normalization ដូចគ្នា។
  4. បន្ថែមតេស្តនៅក្រោម tests/unit/ (ឧទាហរណ៍ដែលមានស្រាប់៖ tests/unit/guardrails-registry.test.ts, tests/unit/prompt-injection-guard.test.ts, tests/unit/guardrails/visionBridge.test.ts)។

ការធ្វើតេស្ត

ប្រើ resetGuardrailsForTests() រវាងតេស្តនីមួយៗ ដើម្បីចាប់ផ្តើមពីស្ថានភាពដែលបានដឹងច្បាស់។ បញ្ជូន { registerDefaults: false } ដើម្បីចាប់ផ្តើមជាមួយ registry ទទេ និង ចុះឈ្មោះតែ guardrail ដែលកំពុងស្ថិតក្រោមការធ្វើតេស្តប៉ុណ្ណោះ។ Vision Bridge ទទួលយកការបញ្ចូល dependency (deps.getSettings, deps.callVisionModel); Audio Bridge ផ្តល់នូវ ចំណុចបំបែកដែលមានតម្លៃសមមូលសម្រាប់ការកំណត់ សមត្ថភាព ការជ្រើសរើសម៉ូដែល STT ការត្រួតពិនិត្យ ព័ត៌មានសម្គាល់អត្តសញ្ញាណ និងការចម្លងសំឡេងជាអត្ថបទ។ ដូច្នេះ តេស្តអាចអនុវត្តលំហូរទាំងពីរដោយមិនចាំបាច់ចូលប្រើ DB ឬបណ្ដាញ។

សូមមើលផងដែរ

  • src/lib/guardrails/ — ការអនុវត្ត
  • src/shared/utils/inputSanitizer.ts — ឧបករណ៍រកឃើញរួមដែលដំណើរការ ការការពារ prompt-injection និងការបិទបាំង PII
  • src/shared/constants/visionBridgeDefaults.ts — តម្លៃលំនាំដើមរបស់ Vision Bridge និង បញ្ជីម៉ូដែល forced-bridge
  • src/shared/constants/modalityBridgeDefaults.ts — តម្លៃលំនាំដើម runtime ដែលប្រើរួមគ្នាសម្រាប់ Vision/Audio
  • docs/architecture/RESILIENCE_GUIDE.md — ស្រទាប់ដាច់ដោយឡែក (circuit breaker, cooldowns)
  • docs/reference/ENVIRONMENT.md — ឯកសារយោងពេញលេញអំពី env var

វិសាលភាព route របស់ injection-guard និង red-team (ដំណាក់កាលទី 8 · ប្លុក D)

injection-guard (createInjectionGuard / withInjectionGuard) គ្របដណ្ដប់ route ទាំងអស់ ដែលទទួលយក prompt របស់អ្នកប្រើ។ វាគោរពតាម INJECTION_GUARD_MODE (លំនាំដើម warn = កត់ត្រា log តែប៉ុណ្ណោះ; block = ត្រឡប់ HTTP 400 SECURITY_001)។

ប្រភេទ Routes មុខងារលំនាំដើម
អត្ថបទ (មានស្រាប់) /v1/chat/completions, /v1/completions, /v1/relay/chat/completions warn
ការបង្កើត /v1/messages, /v1/responses, /v1/images/generations, /v1/images/edits, /v1/videos/generations, /v1/music/generations, /v1/audio/speech warn
ទិន្នន័យ /v1/embeddings, /v1/rerank, /v1/search, /v1/moderations warn

ការស្រង់អត្ថបទ (extractMessageContents) គ្របដណ្ដប់ messages/input/prompt/query+documents/instructions/system

Red-team (រៀងរាល់យប់, nightly-llm-security.yml)៖ promptfoo ផ្ទៀងផ្ទាត់ថា route នីមួយៗរារាំង សំណុំទិន្នន័យ OWASP-LLM ក្នុង INJECTION_GUARD_MODE=block; garak ដំណើរការ probe (រំលងនៅពេលគ្មាន secret)។ moderations ត្រូវបានរួមបញ្ចូលដើម្បីរក្សាភាពស្របគ្នា — ប្រតិបត្តិករក្នុង block-mode អាចលើកលែងវាតាមរយៈ resolveDisabledGuardrails

workflow រៀងរាល់យប់ (.github/workflows/nightly-llm-security.yml, cron + ការបញ្ជូនដោយដៃ) មាន job ចំនួនពីរ៖

  • promptfoo-guard (រារាំង) — ដំណើរការ promptfoo eval -c promptfooconfig.yaml ជាមួយ INJECTION_GUARD_MODE=block។ ករណីវាយប្រហារនីមួយៗ (ឧ. "មិនអើពើ សេចក្ដីណែនាំពីមុនទាំងអស់…", ការ jailbreak បែប DAN) អះអាងថា response មាន error.code === "SECURITY_001" ពោលគឺ guard ពិតជាបានបដិសេធ request។
  • garak (ផ្ដល់ជាអនុសាសន៍) — ដំណើរការ garak --probes promptinject,dan,leakreplay ប្រឆាំងនឹង instance OmniRoute មូលដ្ឋាន (http://localhost:20128/v1)។ វាដំណើរការដោយមានលក្ខខណ្ឌអាស្រ័យលើ provider secret (PROMPTFOO_PROVIDER_KEY); រំលងដោយរលូន ហើយត្រូវបានបន្ថែមនៅខាងចុងដោយ || true ដូច្នេះវារាយការណ៍ដោយមិនធ្វើឱ្យ CI បរាជ័យ។

វិសាលភាពរបស់ guard helper (createInjectionGuard / withInjectionGuard) លាតសន្ធឹងលើ route /v1 ទាំងអស់ដែលមាន prompt; អត្ថបទ prompt ត្រូវបានទាញចេញពី messages/input/prompt/query+documents/instructions/system ដោយ extractMessageContents() ក្នុង src/shared/utils/inputSanitizer.ts