Skip to content

Latest commit

 

History

History
819 lines (685 loc) · 103 KB

GUARDRAILS.md

File metadata and controls

819 lines (685 loc) · 103 KB

Guardrails (Հայերեն)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 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-ի)

Պաշտպանիչ սահմանափակումներն ապահովում են անվտանգությունը, քաղաքականությունների կիրառումը և բովանդակության փոխակերպումները OmniRoute-ի ու վերին մակարդակի մատակարարների միջև ընկած սահմանագծում։ Յուրաքանչյուր պաշտպանիչ սահմանափակում կարող է ստուգել (և ըստ անհրաժեշտության մերժել, փոխակերպել կամ ծանոթագրել) հարցման օգտակար բեռները (preCall) և վերին մակարդակի պատասխանները (postCall)։

Համակարգը գործում է fail-open սկզբունքով․ եթե պաշտպանիչ սահմանափակման կատարման ընթացքում բացառություն է առաջանում, ռեեստրը գրանցում է սխալը և հարցումը ձախողելու փոխարեն շարունակում է հաջորդ պաշտպանիչ սահմանափակմամբ։ Արգելափակումը միշտ բացահայտ որոշում է (block: true) և երբեք՝ պատահականություն։

Ներկառուցված պաշտպանիչներ

Ռեգիստրը ավտոմատ կերպով բեռնում է վեց պաշտպանիչ՝ ըստ առաջնահերթության ներմուծման ժամանակ (տես registry.ts → registerDefaultGuardrails()):

Առաջնահերթություն Անուն Փուլ(եր) Ֆայլ
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

Միջամտում է պատկեր պարունակող հարցումներին, որոնք ուղղված են ոչ տեսողական մոդելներին, և կամ վերաուղղորդում է ամբողջ հարցումը տեսողական մոդելի, կամ փոխարինում է պատկերի մասերը տեքստային նկարագրություններով, որոնք ստեղծվել են կազմաձևվող տեսողական մոդելի կողմից մինչև վերին մակարդակի կանչը։ Սա թույլ է տալիս միայն տեքստային մատակարարներին թափանցիկ կերպով մշակել բազմամոդալ բեռնվածքներ։

Հոսքը:

  1. Բաց թողնել, եթե թիրախային մոդելն արդեն աջակցում է տեսողությանը (բացառությամբ, եթե այն հայտնվում է պարտադրված կամրջի ցուցակում isVisionBridgeForcedModel)։
  2. Հանել պատկերի մասերը extractImageParts(messages)-ի միջոցով (visionBridgeHelpers.ts), որը պատվիրակում է միասնական մեդիա դետեկտորին detectMediaParts() open-sse/utils/mediaParts.ts-ում — ճշմարտության միակ աղբյուրը, որը կիսվում է կոմբո համատեղելիության զտիչի հետ։ Հանումը թույլատրվում է replaceImageParts-ի կողմից հետ տեղադրվող ձևերի վերին մակարդակի մասերին (extract↔replace պայմանագիրը): OpenAI image_url, Anthropic base64 source.type:"base64", Anthropic URL source.type:"url", և Responses API input_image։ Բույն դրված հարվածները և միայն ցուցիչ ձևերը կոմբո-զտիչի նյութ են և երբեք չեն հանվում։ Բաց թողնել, եթե ոչինչ չի գտնվել։
  3. Լուծել runtime կոնֆիգուրացիան resolveVisionBridgeRuntimeSettings()-ի միջոցով (src/shared/constants/modalityBridgeDefaults.ts): նոր modalityBridge* կարգավորումների բանալիները հաղթում են; հին visionBridge* բանալիները մնում են մեկ ցիկլի պահեստային տարբերակ (հետադարձի պատուհան)։ Բաց թողնել ցանկացած մեդիա անցումից առաջ, երբ կամուրջն անջատված է։
  4. Ռեժիմի ընտրիչը (modalityBridgeVisionMode, տես ստորև աղյուսակը) որոշում է վերաուղղորդել, թե նկարագրել։ Վերաուղղորդումը վերադարձնում է modifiedPayload միայն model-ը փոխված, գումարած մետա { rerouted, fromModel, toModel, imagesKept }։
  5. Նկարագրելու ուղին. սահմանափակել պատկերները maxImages-ով, կազմել առաջադրանքին համապատասխան հուշումը, խորհրդակցել նկարագրության քեշի հետ, կանչել տեսողական մոդելը զուգահեռաբար (Promise.allSettled), և ներարկել [Image N]: <description> տեքստային մասերը իրենց տեղում։ Ձախողված նկարագրությունը տալիս է null, և բնօրինակ պատկերի մասը պահպանվում է (#4012) — բացառությամբ կոմբո նկարագրության ուղու, երբ յուրաքանչյուր նկարագրություն ձախողվել է, որտեղ հաստատված ոչ տեսողական վերին մակարդակը ստանում է (unavailable — no vision-capable provider connected) խրոցակ (#8430)։
  6. Վերադարձնել modifiedPayload + մետա (imagesProcessed, descriptions, processingTimeMs, visionModel)։

Ռեժիմի ընտրիչ (modalityBridgeVisionMode)

| Ռեժիմ | Լռելյայն | Վարքագիծ | | ---------- | ------- | Ժառանգական հևրիստիկա, անփոփոխ (#6640/#7204): ոչ կոմբո/auto/ մոդելները վերաուղղորդվում են լավագույն տեսողական մոդելին, եթե բնօրինակ մոդելն արդեն չունի օգտագործելի հավատարմագրեր (ապա նկարագրել); կոմբո թիրախները միշտ նկարագրում են։ | | auto | ✔ | Միշտ նկարագրել — վերաուղղորդման բլոկն ամբողջությամբ բաց է թողնվում; օգտատիրոջ ընտրած մոդելը միշտ պատասխանում է։ | | describe | | Պարտադրել վերաուղղորդումը. հավատարմագրված մոդելի պահպանման պաշտպանիչը շրջանցվում է։ Վերաուղղորդման-թիրախային հավատարմագրի պաշտպանիչը դեռ կիրառվում է — երբ օգտագործելի տեսողական թիրախ գոյություն չունի, հարցումը անցնում է նկարագրելու, որպեսզի հում պատկերները երբեք չհասնեն միայն տեքստային backend-ին (#8430)։ | | reroute | | |

Պարտադրված ռեժիմները կարճ միացում են կատարում մինչև ավտոմատ հևրիստիկայի գործարկումը; auto վարքագիծը բայթ-նույնական է մինչև PR-1 պաշտպանիչին։

Առաջադրանքին համապատասխան նկարագրության հուշում (modalityBridgeVisionTaskAware)

Լռելյայն true։ composeVisionPrompt() (visionBridgeHelpers.ts) ավելացնում է վերջին օգտատիրոջ հաղորդագրության տեքստը (կտրված մինչև 500 նիշ) հիմնական նկարագրության հուշմանը, ուղղորդելով նկարագրությունը դեպի այն, ինչ օգտատերն իրականում խնդրել է (codex-vision-proxy օրինակ) և խնդրելով տեսողական մոդելին արտագրել տեսանելի տեքստը։ Եթե դրոշակն անջատված է — կամ օգտատիրոջ տեքստ չկա — հիմնական հուշումն օգտագործվում է անփոփոխ։

describe ինքնաշրջանի սեփական OpenAI-համատեղելի հարցումը (callVisionModelSingle() visionBridgeHelpers.ts-ում) միշտ հարցնում է image_url.detail: "high" — անվերապահորեն, յուրաքանչյուր զանգահարողի/մատակարարի համար, առանց որևէ հաճախորդի ազդանշանի։ Ցածր մանրամասնության նմուշառումը վատթարացնում է OCR-ի ճշգրտությունը հենց այն տեքստի-տառադարձման խնդրի համար, որը պահանջում է այս հուշումը, ուստի describe զանգը ինքնին միշտ պահանջում է բարձր մանրամասնություն՝ անկախ նրանից, թե ինչ մանրամասնության մակարդակ է օգտագործել սկզբնական մուտքային հարցումը։ Սա ազդում է միայն ներքին describe հարցման մարմնի վրա. այն չի փոխում, թե ինչպես է OmniRoute-ը փոխանցում զանգահարողի սեփական image_url.detail-ը հիմնական հարցման վրա — այդ լռելյայնը կիրառվում է առանձին, և միայն հայտնաբերված OpenCode հաճախորդների համար, defaultImageDetail()-ում (open-sse/handlers/chatCore/upstreamBody.ts)։ describe ինքնաշրջանի Anthropic wire-format ճյուղը չունի detail դաշտ և չի ազդում ոչ մի լռելյայնից։

Նկարագրության ելքի սահմանափակումը (modalityBridgeVisionMaxChars)

Բանալի Լռելյայն Միջակայք
modalityBridgeVisionMaxChars 0 0 կամ 100–50000

0 (լռելյայն) նշանակում է առանց սահմանափակման — callVisionModel()-ի կողմից վերադարձված նկարագրությունը փոխանցվում է անփոփոխ, պահպանելով առկա վարքագիծը։ 100–50000 միջակայքի ցանկացած արժեք կտրում է նկարագրությունը … վերջածանցով, նախքան այն հետ կմիացվի որպես [Image N]: <description> (VisionBridgeGuardrail.preCall() src/lib/guardrails/visionBridge.ts-ում)։ Բարձրացրեք սա մանրամասն OCR խնդիրների համար, որտեղ ներքևի մոդելին անհրաժեշտ է ամբողջական տառադարձումը. իջեցրեք այն՝ զրուցող տեսողական մոդելների վրա թոքենների օգտագործումը սահմանափակելու համար։ Վահանակի դաշտը գտնվում է Vision ներդիրի Advanced վահանակում (modality-bridge-max-chars ModalityBridgeVisionTab.tsx-ում) և ցանկացած արժեք 1-ից 99-ի միջև սահմանափակում է մինչև 100-ի ստորին շեմը՝ թողնելով բացահայտ 0-ը անձեռնմխելի — 0-ը ինքնին վավեր Zod արժեք է (z.union([z.literal(0), z.number().int().min(100).max(50000)])), ոչ թե պարզապես «չսահմանված» լռելյայն։

Նկարագրության քեշ (modalityBridge/bridgeCache.ts)

Հիշողության մեջ LRU + TTL քեշ նկարագրության ելքերի համար, որը կիսվում է ամբողջ գործընթացով։ Բանալին = sha256(imageRef + composedPrompt + configuredBridgeModel) երկարության-նախածանցային շրջանակով (առանց դաշտի-սահմանի բախումների)։ Մոդելի բաղադրիչը կարգավորված կամրջի մոդելն է, ոչ թե այն մոդելը, որն իրականում պատասխանել է — callVisionModel-ը կարող է ներքինորեն հետ ընկնել, և յուրաքանչյուր փորձի համար բանալիավորումը կքանդեր քեշը։ Ձախողված նկարագրությունները երբեք չեն քեշավորվում։ Կարգավորումներ.

Բանալի Լռելյայն Միջակայք
modalityBridgeCacheEnabled true —
modalityBridgeCacheTtlMinutes 60 1–1440
modalityBridgeCacheMaxEntries 200 10–5000

Հեռավոր պատկերի նորմալացում (ինքնաշրջանային նկարագրություն/base64 բեռնում)

Երբ կամուրջը ինքն է բեռնում հեռավոր պատկեր — Anthropic-ի նկարագրության ինքնազանգը և claude-wire-format base64 փոխակերպումը (ensureBase64ImagesForClaudeWire), երկուսն էլ fetchRemoteImageAsDataUri()-ի միջոցով visionBridgeHelpers.ts-ում — ստացված տվյալների URI-ն անցնում է normalizeDataUri()-ի միջով (open-sse/utils/imageNormalize.ts), նախքան տեսողական մոդելի հարցման մեջ ներդրվելը։ Չափից մեծ պատկերները փոքրացվում են մինչև 2048px երկար կողմ (համապատասխանելով OpenAI/Anthropic-ի կողմից արդեն սերվերի կողմից կիրառվող չափափոխման սահմանափակմանը), ինչը կրճատում է վերբեռնման բայթերը/ուշացումը՝ առանց փոխելու այն, ինչ տեսնում է տեսողական մոդելը։ Չափափոխումը օգտագործում է sharp, որը բեռնվում է դինամիկ ներմուծման միջոցով. այն հարթակում, որտեղ դրա բնիկ երկուական ֆայլը չի բեռնվում, normalizeDataUri()-ը երբեք սխալ չի տալիս — այն հետ է ընկնում բնօրինակ բայթերի փոխանցմանը, ուստի նկարագրության/base64-փոխակերպման ուղին միշտ շարունակում է աշխատել։ Ոչ պատկերային բայթերը (բեռնում, որը չի վերադարձրել վերծանվող պատկեր) նույնպես փոխանցվում են անձեռնմխելի։ Այս նորմալացումը վերաբերում է այն պատկերներին, որոնք կամուրջը բեռնում է իր ինքնազանգի համար — այն երբեք չի կիրառվում զանգահարողի հում փոխանցման բեռնվածքի վրա, համահունչ միայն ընտրովի փոփոխության սկզբունքին (Կոշտ կանոն #20)։

Կարգավորումների սխեմա + միգրացիա

Նոր modalityBridge* բանալիները Zod-ով վավերացվում են updateSettingsSchema-ում (src/shared/validation/settingsSchemas.ts): modalityBridgeVisionEnabled, modalityBridgeVisionMode, modalityBridgeVisionModel, modalityBridgeVisionTaskAware, modalityBridgeVisionPrompt, modalityBridgeVisionTimeout, modalityBridgeVisionMaxImages, modalityBridgeVisionMaxChars, modalityBridgeCache* եռյակը, և modalityBridgeAudio* խումբը, որն օգտագործվում է Audio Bridge-ի կողմից։ Միգրացիա 141_modality_bridge_settings.sql-ը պատճենում է առկա հին visionBridge* արժեքները համապատասխան նոր բանալիներին (իդեմպոտենտ, երբեք չի վերագրում օպերատորի կողմից սահմանված modalityBridge* արժեքը); հին բանալիները մնում են ընդունված որպես կարդալու պահեստային տարբերակ մեկ թողարկման ցիկլի համար։

Թափանցիկության վերնագիր + վիճակագրություն

Նկարագրությամբ փոխակերպված պատասխանները կրում են x-omniroute-modality-bridge: image->text;model=<visionModel>;parts=<n> (կառուցված է buildModalityBridgeHeader()-ի կողմից modalityBridge/bridgeStats.ts-ում, կնքված է withModalityBridgeHeader()-ի կողմից src/sse/handlers/chatHelpers.ts-ում)։ Վերաուղղորդված հարցումները չեն ստանում վերնագիր — բեռնվածքը անձեռնմխելի է մնացել, և մոդելի փոխանակումն արդեն տեսանելի է պատասխանի մարմնի model դաշտում։

GET /api/modality-bridge/stats (կառավարման թույլտվություն, նույն մակարդակը, ինչ GET /api/settings) վերադարձնում է հիշողության մեջ յուրաքանչյուր մոդալության հաշվիչները { attempts, successes, bridged, cacheHits, failures, totalLatencyMs, latencySamples, averageLatencyMs, lastUsedAt } vision, audio և video-ի համար։ averageLatencyMs-ը օգտագործում է latencySamples, ոչ թե բոլոր փորձերը, որպես իր հայտարար. ժամանակավորում չունեցող գործողությունը զրո-միլիվայրկյան նմուշ չի ստեղծում։ bridged-ը մնում է հետադարձ համատեղելի մականուն հաջող փոխակերպումների համար. ձախողված փորձերը չեն ավելացնում այն։ Հաշվիչները վերականգնվում են գործընթացի վերագործարկման ժամանակ ըստ նախագծի (հեռաչափություն, ոչ հաշվապահություն)։

Վահանակի կոնֆիգուրացիա

Նվիրված վահանակի էջը /dashboard/settings/modality-bridge է։ Դրա URL-ով հասանելի Vision, Audio և Video ներդիրները պահպանում են հարցման պարամետրերը՝ միաժամանակ փոխելով tab արժեքը։ Vision ներդիրը բացահայտում է միացումը, ռեժիմը, մոդելի ընտրությունը (ներառյալ ավտոմատ լռելյայնը), առաջադրանքին համապատասխան հուշումները, ընդլայնված ժամանակի սահմանաչափերը/պատկերների/նկարագրության երկարության/քեշի սահմանաչափերը, կատարման հաշվիչները և պաշտպանված նմուշի հարցումը։ Audio ներդիրը նույնպես ակտիվ է. այն բացահայտում է միացումը, STT-միայն մոդելի ընտրիչը Auto-ով, ժամանակի սահմանաչափերը/առավելագույն կլիպի սահմանաչափերը, աուդիո հաշվիչները և input_audio նմուշի թեստը։ Video ներդիրը ֆունկցիոնալ է. այն հաղորդում է FFmpeg/ffprobe-ի կատարման վիճակը՝ չորս հստակ UI վիճակներից մեկը (unknown մինչդեռ զոնդը գործում է կամ չի կարողացել ավարտվել, restricted ոչ-loopback վահանակի հոսթի վրա, որտեղ զոնդը բաց է թողնվում հաճախորդի կողմից, unavailable զոնդավորվելուց և բացակայությունը հաստատվելուց հետո, կամ available FFmpeg/ffprobe տարբերակներով) — պահպանում է միացման/մոդելի/կադրի/տեսանյութի/ժամանակի սահմանաչափերը, զտում է մոդելի ընտրիչը տեսողական հնարավորություններ ունեցող մոդելների համար և բացահայտում է տեսանյութի հաշվիչները։

Նախկին Vision Bridge քարտը AI կարգավորումների ներքո համատեղելիության հղում է դեպի նոր էջը. այն այլևս չունի ձևի երկրորդ պատճենը։ Media Providers-ը նաև կապում է Image-to-Text և Speech-to-Text աշխատանքային հոսքերը համապատասխան Modality Bridge ներդիրներին՝ առանց առկա Speech-to-Text խաղահրապարակը հեռացնելու։

Self-loop մուտքի շրջանցում. երբ նկարագրության կանչը OmniRoute-ի սեփական /v1 self-loop-ի միջոցով է (ոչ ստանդարտ մատակարարի մոդել), ենթահարցումն ուղարկում է x-omniroute-admission-bypass: internal և վավերացվում է լուծված self-loop հավատարմագրով՝ տեղական sk_omniroute պահակը տեղական ռեժիմում, կամ օպերատորի կողմից կազմաձևված OMNIROUTE_API_KEY / ROUTER_API_KEY միջավայրի բանալին (#1350), որպեսզի REQUIRE_API_KEY=true տեղակայումները դեռ կարողանան կատարել նկարագրության կանչը։ Շրջանցումը հարգվում է միայն այդ ճշգրիտ հավատարմագրերի համար, ուստի արտաքին հաճախորդները չեն կարող օգտագործել վերնագիրը մուտքը բաց թողնելու համար։

Հին լռելյայն արժեքները գտնվում են src/shared/constants/visionBridgeDefaults.ts-ում. նոր ռեժիմի/առաջադրանքին համապատասխան/քեշի լռելյայն արժեքները և կարգավորումների լուծիչը գտնվում են src/shared/constants/modalityBridgeDefaults.ts-ում։ Պաշտպանիչ մեխանիզմը բացահայտում է deps կոնստրուկտորի տարբերակը, որպեսզի թեստերը կարողանան ներարկել կեղծ getSettings և callVisionModel իրականացումներ։

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

Արգելափակում է ձայն պարունակող չաթի հարցումները, նախքան դրանք կհասնեն այն թիրախին, որը հայտնի չէ, որ ընդունում է ձայնային մուտք։ Այն երբեք չի վերաուղղորդում չաթի հարցումը. ձայնային մասերը տառադարձվում են առկա OpenAI-համատեղելի բազմամաս վերջնակետի միջոցով, և ընտրված չաթի մոդելը շարունակում է տեքստային տառադարձերով։

Հոսքը.

  1. Լուծել supportsAudio-ն getResolvedModelCapabilities()-ի միջոցով։ Հստակ մատակարար-ռեգիստրի մետատվյալները հաղթում են, այնուհետև ստատիկ մոդելի մետատվյալները, այնուհետև համաժամեցված modalities_input-ը։ Հայտարարված մուտքային ցուցակը առանց audio-ի false է. ունակության ապացույցի բացակայությունը մնում է null։ Ե՛վ false-ը, և՛ null-ը ակտիվացնում են պահպանողական կամուրջը, մինչդեռ true-ն շրջանցում է այն։
  2. Լուծել modalityBridgeAudio* կարգավորումները և արդյունահանել բաժանելի վերին մակարդակի ձայնային մասերը յուրաքանչյուր հաղորդագրությունից՝ ընդհանուր detectMediaParts() դետեկտորի միջոցով։ Աջակցվող մետաղալարերի ձևերն են OpenAI input_audio, audio_url և source.media_type: "audio/*"։ Բույն դրված ձայնը հայտնաբերվում է երթուղիավորման համար, բայց չի հեռացվում բաժանման ուղու միջոցով։ Աշխատանքը սահմանափակվում է modalityBridgeAudioMaxClips-ով. ավելի ուշ մասերը մնում են անձեռնմխելի։
  3. Հարգել կազմաձևված provider/model-ը, կամ թույլ տալ selectAudioBridgeModel()-ին անցնել AUDIO_TRANSCRIPTION_PROVIDERS-ի միջով կայուն կատալոգի կարգով և ընտրել առաջին մոդելը՝ օգտագործելի ակտիվ մատակարարի հավատարմագրով։
  4. callAudioTranscription()-ը base64/data-URI ձայնը փոխակերպում է բազմամաս file-ի, կամ ներբեռնում է հեռավոր audio_url հանրային-միայն արտաքին պաշտպանիչի միջոցով՝ DNS ամրացմամբ և 25 ՄԲ սահմանաչափով։ Այնուհետև այն POST է անում ֆայլը և ընտրված մոդելը տեղական /v1/audio/transcriptions self-loop-ին, վավերացված resolveSelfLoopBearer()-ով։ Առկա տառադարձման երթուղին կատարում է սովորական հավատարմագրի որոնում, սառեցման/սահմանաչափի մշակում և մատակարարի ուղարկում։
  5. Հաջող կանչերը փոխարինում են իրենց մասերը [Audio N]: <transcript>-ով։ Կանչերը գործում են Promise.allSettled-ով. անհատական ձախողումը պահպանում է այդ բնօրինակ ձայնային մասը (#4012 պայմանագիր)։ Եթե յուրաքանչյուր կանչ ձախողվում է, և թիրախը ապացուցված է supportsAudio === false, ապա մասերը դառնում են [Audio N]: (unavailable — no STT provider connected) (#8430 պայմանագիր)։ Անհայտ թիրախի (null) դեպքում բոլոր ձախողումների արդյունքը մնում է անձեռնմխելի։ Ապացուցված տեքստային-միայն թիրախը՝ առանց օգտագործելի STT հավատարմագրի, ստանում է նույն հստակ խրոցակը՝ առանց ցանցային կանչ կատարելու։

Հաջող տառադարձերը օգտագործում են գործընթացի լայն Modality Bridge LRU/TTL քեշը։ Բանալին համատեղում է ձայնային հղումը, կայուն audio-transcription գործողության պիտակը և ընտրված STT մոդելը. ձախողումները երբեք չեն քեշավորվում։ Ձայնային փորձերը թարմացնում են ընդհանուր bridged, cacheHits, failures և lastUsedAt հաշվիչները։ Փոխակերպված պատասխանները կրում են x-omniroute-modality-bridge: audio->text;model=<sttModel>;parts=<n>; անձեռնմխելի հարցումները չեն ստանում Audio Bridge հատված։

Կատարման կարգավորումները DB-ի վրա հիմնված են և Zod-ով վավերացված.

Key Default Range
modalityBridgeAudioEnabled true —
modalityBridgeAudioModel "" Auto կամ STT ID
modalityBridgeAudioTimeout 60000 1000–300000
modalityBridgeAudioMaxClips 3 1–10

Ընդհանուր քեշը մնում է վերահսկվող modalityBridgeCacheEnabled, modalityBridgeCacheTtlMinutes և modalityBridgeCacheMaxEntries միջոցով։

Video Bridge (videoBridge.ts, videoBridgePipeline.ts)

Որսում է բարձր մակարդակի տեսանյութի մասեր Chat Completions messages-ում և Responses API input-ում՝ նախքան թիրախի կանչվելը՝ առանց հայտնի բնիկ տեսանյութի աջակցության: Աջակցվող ձևերն են՝ input_video, video_url, video_source, HTTPS URL-ներ, և data:video/*;base64,... տվյալների URI-ներ: Տեքստում սովորական ֆայլերի անունները չեն դիտարկվում որպես տեսանյութ:

VideoBridgeGuardrail.preCall (videoBridge.ts) ապահովում է հարցումների անցումը, հնարավորությունների/քաղաքականության ստուգումը, ըստ հարցումների ագրեգացումը և պատասխանի բեռնվածությունը: Յուրաքանչյուր տեսանյութի աշխատանքը՝ ձեռքբերումը, ամբողջական արդյունքի քեշը, կադրերի հաջորդականության նկարագրությունը (որը միաձուլում է ցանկացած կանչողի կողմից հայտարարված աուդիո տրանսկրիպտը) և յուրաքանչյուր փորձի չափումները/ընդհատումը/մաքրումը թաքնված է processVideoPart-ի հետևում՝ videoBridgePipeline.ts-ում, որը կանչվում է մեկ անգամ յուրաքանչյուր տեսանյութի մասի համար preCall-ի ցիկլի ներսում: Այդ մոդուլը նաև սահմանում է հստակ պորտերի սահմանները՝ VideoMediaBrokerPort (բայթերի ձեռքբերում և նմուշառված կադրերի արդյունահանում), VideoAudioTranscriptionPort (կանչողի կողմից հայտարարված աուդիո տրանսկրիպտի միաձուլում նմուշառված ենթագրերի հետ) և VideoDrilldownPort (կադրերի մանրամասնության պահպանման սահմանը. դեռևս միացված չէ processVideoPart-ին. այսօր միայն առանձին /api/modality-bridge/video/drilldown երթուղին է գրում մանրամասնության գրառումներ):

Հանրային /v1 հարցումների ուղին երբեք չի ներմուծում կամ կանչում ենթապրոցես: Հեռավոր տեսանյութերը ներբեռնվում են 50 ՄԲ սահմանաչափով. ներկառուցված base64 տեսանյութերը ունեն պահպանողական 36 ՄԲ ապակոդավորված յուրաքանչյուր տեսանյութի սահմանաչափ, որպեսզի մոդելը/հաղորդագրությունները/կադրավորման ծրարը մնան 50 ՄԲ հանրային JSON հարցումների ընդունման սահմանաչափի ներսում: Ներկառուցված երկարության և ապակոդավորված չափի գնահատումները ստուգվում են նախքան հատկացումը: HTTPS-ը պահանջվում է սկզբնական հեռավոր URL-ի և յուրաքանչյուր վերահղման համար՝ օգտագործելով գոյություն ունեցող միայն հանրային ելքային պաշտպանությունը DNS ամրացումով: Այնուհետև բայթերը հատում են ճշգրիտ ներքին POST /api/modality-bridge/video/extract բրոքերի սահմանը: Այդ երթուղին և՛ LOCAL_ONLY է, և՛ SPAWN_CAPABLE, ընդունում է միայն յուրաքանչյուր պրոցեսի համար վավերացված, վստահելի լուփբեք հարցում և երբեք չի ընդունում URL, ֆայլային համակարգի ուղի, կատարվող ֆայլ կամ արգումենտների ցուցակ: API մարմնի չափի խողովակաշարը և հենդլերի աճող մարմնի ընթերցիչը անկախաբար կիրառում են 50 ՄԲ բրոքերի մուտքային սահմանաչափ: Դրա սահմանափակ հերթը միաժամանակ կատարում է մեկ արդյունահանում, թույլ է տալիս չորս սպասվող աշխատանք և սահմանափակում է սպասվող մուտքը 100 ՄԲ-ով:

Բրոքերի ներսում ffprobe-ը կարդում է մասնավոր տեղական ֆայլ. ֆիքսված ձևաչափի թույլատրված ցուցակը բացառում է երգացանկի և մանիֆեստի ձևաչափերը: Թույլատրված MOV-ընտանիքի կոնտեյներների համար արտաքին MOV տվյալների հղումները մնում են անջատված լռելյայն, և ֆիքսված հրամանը դրանք չի ընդունում: Ե՛վ ffprobe-ը, և՛ ffmpeg-ը օգտագործում են միայն file արձանագրության սպիտակ ցուցակը, մեկ թել, ֆիքսված արգումենտների զանգվածներ, առանց shell-ի և PATH-ից լուծված կատարվող ֆայլեր: Կցված նկարի շապիկի հոսքերը նվագարկվող թեկնածուներ չեն: Բոլոր նվագարկվող հոսքերը պետք է բավարարեն սահմանափակումները, և հստակ լռելյայն հոսքը նախընտրելի է մինչև դետերմինիստական ամենացածր ինդեքսի անկումը: Տեսանյութերը սահմանափակված են 600 վայրկյանով, 8,192 պիքսելով յուրաքանչյուր չափումով և 33,554,432 աղբյուրի պիքսելներով: FFmpeg-ը նմուշառում է 1–16 միջին JPEG կադրեր, փոքրացնում է երկար կողմը մինչև առավելագույնը 1,024 պիքսել՝ առանց փոքր մուտքերի մեծացման, և երբեք չի ստանում URL: Նմուշառումը լռելյայն uniform է: Ընտրովի scene_aware և փորձարարական segment_aware քաղաքականությունները կատարում են մեկ լրացուցիչ ֆիքսված FFmpeg անցում արդեն վավերացված տեղական հոսքի վրայով, ընտրում են սահմանափակ showinfo տեսարանի ժամանակային դրոշմներ և դետերմինիստորեն վերադառնում են նույն միատեսակ միջին կետերին՝ դետեկտորի ձախողման, ժամանակի սպառման, սխալ ձևավորված ելքի կամ դատարկ թեկնածուների հավաքածուի դեպքում: Սեգմենտի գիտակցված ռեժիմը հատկացնում է միջին կետի նմուշներ՝ համաչափ վավերացված տեսարանի ինտերվալներին. սեգմենտի գիտակցված ապացույցները և անկման վարքագիծը մանրամասնված են ստորև: Կոշտ 16-կադրային սահմանաչափը կիրառվում է ընտրությունից հետո յուրաքանչյուր քաղաքականության մեջ: Երբ տեսարանին գիտակցված հարցումը ունի ընդամենը մեկ կադրի բյուջե, այն օգտագործում է ակտիվ ամբողջական տեսանյութի կամ ֆոկուսի պատուհանի միատեսակ միջին կետը և հաղորդում է policyEffective: uniform. մեկ ընտրված տեսարանի կադրը չի կարող պահպանել երկու ժամանակային ծայրերը: Կանչողը կարող է ընտրովիորեն տրամադրել վերջավոր ֆոկուսի պատուհան (start/end վայրկյաններ). սահմանները սեղմվում են մեդիայի տևողությանը, շրջված կամ անվերջ պատուհանները մերժվում են, և բոլոր նմուշառման քաղաքականությունները կատարվում են միայն նորմալացված ինտերվալի ներսում: Արդյունքում ստացված պատուհանը ներառվում է նմուշառման մետատվյալներում և անվստահելի նկարագրության նախածանցում, որպեսզի ներքևի մոդելները կարողանան տարբերել կենտրոնացված հատվածը ամբողջ ժամանակացույցից:

Սեմանտիկ ենթագրերի ֆոկուսը առանձին, հստակ կարգավորում է: Լռելյայն full վերլուծության ռեժիմը պահպանում է գոյություն ունեցող կադրի հուշումը և երբեք չի փոխանցում հարցման տեքստը ենթագրերի մոդելին: focused ռեժիմում կամուրջը կարդում է միայն վերջին ոչ դատարկ օգտատիրոջ կողմից ստեղծված text/input_text նույն Chat կամ Responses կոնտեյներից, նորմալացնում է այն NFC-ին, փլուզում է կառավարման նիշերը և բացատները և սահմանափակում է այն 500 Unicode կոդային կետերով: Դատարկ արդյունքը վերադառնում է ճշգրիտ full հուշմանը: Օգտագործելի հուշումը սերիալիզացվում է որպես JSON հատուկ անվստահելի օգտատիրոջ համատեքստի բլոկում և կարող է միայն առաջնահերթություն տալ դիտարկելի մանրամասներին. այն չի կարող չեղարկել առանձին նախազգուշացումը մեդիայում տեսանելի կամ լսելի հրահանգներին հետևելու դեմ: Տեքստային ֆոկուսը երբեք չի ենթադրում start/end կամ չի փոխում ժամանակային նմուշառիչը:

FU-07 կառուցվածքային հատվածի ապացույց

segment_aware-ը օգտագործում է մեկ սահմանափակ նախնական վերլուծության անցում արդեն վավերացված տեղական տեսանյութի հոսքի վրայով: Ֆիքսված ֆիլտրի շղթան նախ սանդղակավորում է մինչև առավելագույնը 320 պիքսել լայնությամբ, հայտնաբերում է տեսարանի փոփոխությունները և սառեցված ինտերվալները, այնուհետև նմուշառում է 1 կադր վայրկյանում՝ լղոզման, միջին լյումայի և տարածական/ժամանակային տեղեկատվության համար: Անցումը սահմանափակված է 600 կառուցվածքային նմուշներով, մեկ FFmpeg/ֆիլտրի թելով, նույն file-միայն արձանագրության և կոնտեյների թույլատրված ցուցակներով, 1 ՄԲ պրոցեսի ելքային սահմանաչափով և առավելագույնը 30 վայրկյանով բրոքերի ընդհանուր ընդհատման/վերջնաժամկետի ներսում: Այն երբեք չի ընդունում հրաման, ֆիլտր, ուղի կամ URL հարցումից:

Կառուցվածքային արժեքները դետերմինիստական նմուշառման ապացույցներ են, ոչ թե իմաստային տեսանյութի ընկալում։ Դրանք չեն ենթադրում առարկաներ, գործողություններ, ենթագրեր, խոսք կամ օգտատիրոջ մտադրություն։ Տեսարանների և սառեցման սահմանները ձևավորում են հատվածներ. սառեցման ծածկույթը, լղոզումը, լուսարձակումը, տարածական մանրամասները և ժամանակավոր փոփոխությունները միայն ազդում են, թե ինչպես է բաշխվում առկա 1–16 կադրերի բյուջեն։ Ամբողջությամբ սառեցված հատվածը սահմանափակվում է մեկ կադրով, մինչդեռ չսառեցված հատվածները մրցում են մնացած բյուջեի համար։ Երբ սահմանները գերազանցում են կադրերի քանակը, պահպանվում է ժամանակացույցի միատեսակ ծածկույթը, որպեսզի արագ վաղ կտրվածքները չկարողանան թաքցնել երկար հետևող հատվածը։ Սառեցման սահմանի 1 վայրկյանի վերլուծության լուծաչափի ներսում գտնվող տեսարանների սահմանները միաձուլվում են։

Բացակայող ֆիլտրերը, սխալ ձևավորված/դատարկ ապացույցները, դետեկտորի սխալը կամ սահմանափակված նախնական վերլուծության ժամանակի սպառումը բաց են թողնում ճշգրիտ միատեսակ միջին կետի քաղաքականությանը։ Զանգահարողի ընդհատումը կամ բրոքերի վերջնաժամկետը բաց չի թողնում. այն դադարեցնում է ընթացիկ ենթապրոցեսը, կանխում է հետագա կադրերի արդյունահանումը, և մասնավոր ժամանակավոր ծառը հեռացվում է finally-ում։

scripts/perf/video-bridge-fu07-eval.ts-ը ստեղծում է դետերմինիստական իրական FFmpeg ֆիքսատորներ՝ հետ-դեդուպ ենթագրերի կանչերի խնայողությունների, խիտ շարժման բյուջեի բաշխման, լղոզման/լուսարձակման/SI-TI ապացույցների, երկար պոչով արագ կտրվածքների և աստիճանական մարման կեղծ դրական արդյունքների համար։ Այն գրանցում է նախնական վերլուծության պատի ժամանակը և, որտեղ /usr/bin/time-ը հասանելի է, երեխա CPU-ի և գագաթնակետային RSS-ի տվյալները։ Դրա որակի ստուգումները միայն կառուցվածքային օրակուլներ են։ Իրական ենթագրերի մոդելի որակը մնում է HOLD, քանի որ այս հարմարանքը չունի լիազորված վերջնակետ կամ սառեցված դատավոր։ Դրամական խնայողությունները նույնպես մնում են HOLD, եթե --caption-cost-per-call-usd-ը չի տրամադրում հստակ դրական մեկ կանչի գնահատական. սկրիպտը երբեք չի կեղծում որևէ արդյունք։

Յուրաքանչյուր կադր սահմանափակված է 4 ՄԲ-ով, բոլոր հում կադրերը միասին՝ 23 ՄԲ-ով, իսկ սերիալիզացված բրոքերի պատասխանը՝ 32 ՄԲ-ով։ Մասնավոր ժամանակավոր գրացուցակը հեռացվում է finally-ում։ OmniRoute-ը չի փաթեթավորում FFmpeg-ը և չի ընդունում հատուկ կատարվող ճանապարհ։ Ենթագրելուց առաջ կամուրջը կիրառում է պահպանողական վիզուալ կրկնօրինակման անցում. յուրաքանչյուր JPEG նվազեցվում է մինչև 16×16 գորշ երանգների բուֆեր և համեմատվում է միայն պահպանված վերջին կադրի հետ։ Մեկ կադրից ավելի պահանջվող ենթագրերի բյուջեի համար արդյունահանումը տրամադրում է սահմանափակ թեկնածուների հավաքածու՝ մինչև այդ բյուջեի կրկնապատիկը և երբեք ավելի քան 16 կադր։ Պահանջվող սահմանափակումը կիրառվում է միայն կրկնօրինակումից հետո, ընտրված առաջին և վերջին թեկնածուները պահպանվում են վերջնական նոսրացման ժամանակ, երբ բյուջեն առնվազն երկու է։ Տարբերակված grayscale-16x16-mean-cells-v2 քաղաքականությունը օգտագործում է միջին լյումա դելտայի և մանրապատկերների բջիջների հարաբերակցության ավելի մեծը, որոնց նորմալացված դելտան առնվազն 0.05 է։ Կրկնօրինակման շեմը հաստատուն 0.04 է, որն ընտրված է կանխատեսելիության համար, այլ ոչ թե բացահայտված որպես գործարկման կարգավորում։ Այս երկրորդական բարձր կոնտրաստի ազդանշանը պահպանում է փոքր շարժումները և տեսանելի տեքստի փոփոխությունները, որոնք միայն միջինի համեմատությունը կարող է թաքցնել։ Համեմատիչի կամ դեկոդերի սխալները բաց են թողնում և պահպանում ծածկույթը։ Ելքային մետատվյալները առանձնացնում են արդյունահանված թեկնածուները, հաջողությամբ օգտագործված կադրերը և հեռացված վիզուալ կրկնօրինակները։

Հստակ նշված տեսանյութի մասը կարող է պահանջել ժամանակային կոնտակտային թերթիկ։ Կամուրջը կառուցում է առավելագույնը 4 սյունակից, 16 կադրից բաղկացած JPEG ցանց։ Յուրաքանչյուր 512 պիքսելանոց բջիջը իր աղբյուրի ժամանակային դրոշմը այրում է բարձր կոնտրաստի ներքևի շերտի մեջ, մինչդեռ նույն ժամանակային դրոշմները մնում են տեքստային մետատվյալներում՝ հետագա կապի և աուդիտի համար։ Ամբողջական JPEG-ը մնում է սահմանափակված 32 ՄԲ-ով։ Եթե sharp-ը չի կարողանում վերծանել կամ կազմել ցանցը, կամուրջը վերադառնում է առանձին JPEG կադրերին. հաճախորդի ընդհատումը դեռևս տարածվում է թերթիկի գործողության միջոցով։

Խթանման ապացույցները միտումնավոր առանձնացված են սինթետիկ կոմպոզիցիայի միկրոբենչմարկից։ scripts/perf/video-bridge-contact-sheet-eval.ts-ը սահմանում է սխեմա-տարբերակված A/B հարմարանք իրական OpenAI-համատեղելի տեսողական մոդելների համար։ Այն չափում է մատակարարի կողմից հաղորդված թոքենները, վերջից-վերջ պատի ուշացումը (ներառյալ թերթիկի կոմպոզիցիան), մոդելի կանչերի քանակը և մանիֆեստով սահմանված փաստերի պահպանումը։ Հում մոդելի պատասխանները չեն գրվում զեկույցում. պահպանվում են միայն SHA-256 ամփոփագրերը և համապատասխան փաստերի ID-ները։ Հարմարանքը ցանցային կամ վճարովի մոդելի կանչ չի կատարում, եթե --execute-real-ը չի փոխանցվում և --model, OMNIROUTE_BASE_URL և OMNIROUTE_API_KEY չեն կազմաձևվում։ Առանց այդ հստակ իրական գործարկման, դրա մեքենայական ընթեռնելի վճիռը մնում է HOLD. սինթետիկ բեռնվածության/կանչերի քանակի չափումները միայն խթանման ապացույց չեն։

Զանգահարողները կարող են կցել կամընտիր transcript.cues զանգվածը աջակցվող տեսանյութի մասին, երբ նրանք արդեն ունեն համաձայնեցված տեքստ։ Յուրաքանչյուր ազդանշան պետք է պարունակի text, վերջավոր start/end միջակայք զննված տևողության ներսում և սպիտակ ցուցակում ներառված source (client, embedded կամ audio-bridge). confidence-ը լռելյայն 1 է և պետք է մնա 0-ի և 1-ի միջև։ Ճշգրիտ կրկնօրինակ ազդանշանները միաձուլվում են։ OmniRoute-ը երբեք չի սկսում տառադարձումը այս մետատվյալներից. վավերացված ազդանշանները պատճենվում են նկարագրված արդյունքի մեջ՝ աղբյուրով, վստահությամբ և միջակայքով, և ներկայացվում են որպես անվստահելի դիտարկումներ՝ կադրերի ենթագրերի կողքին։ Անվավեր, միջակայքից դուրս կամ ծագումնաբանությունից զուրկ տեքստը մերժվում է, այլ ոչ թե խառնվում ենթագրերի հոսքի մեջ։ source դաշտը ներկայումս հայտարարվում է զանգահարողի կողմից, ոչ թե սերվերի կողմից ստուգվում. OmniRoute-ը պարտադրում է, որ արժեքը լինի երեք թույլատրված տողերից մեկը, բայց դեռևս գաղտնագրորեն չի հաստատում, որ embedded կամ audio-bridge պիտակը իրականում սերվերի սեփական արդյունահանումից է։ Վերաբերվեք source-ին որպես անվստահելի հուշում, մինչև այդ ստուգումը տեղի ունենա. մի կառուցեք թույլտվության որոշումներ դրա վրա։

Առաջադեմ զանգահարողը կարող է տրամադրել արդեն թույլատրված audioTranscript հետք նույն տեսանյութի համար։ Ֆյուժնի կարը տեսողական և ձայնային դիտարկումները միավորում է մեկ վերջնաժամկետի և ընդհատման ազդանշանի ներքո, դրանք դասավորում է ընդհանուր ժամանակացույցի վրա, միավորում է ճշգրիտ կրկնօրինակները և հաղորդում մասնակի արդյունք, երբ միայն մեկ կողմն է հաջողում։ Անվավեր audioTranscript-ը վերածվում է այդ մասնակի արդյունքի՝ տեսողական նկարագրությունը պահպանվում է, իսկ ձայնային ճյուղը գրանցում է մաքրված ձախողման կոդ՝ ամբողջ տեսանյութը ձախողելու փոխարեն։ Յուրաքանչյուր ճյուղի հասանելիությունը, մասնակի դրոշը և մաքրված ձախողման կոդերը պահպանվում են նկարագրված արդյունքում, պաշտպանիչ մետատվյալներում (audioFusionRuns/audioFusionPartials/ audioFusionFailureCodes), արդյունքների քեշի մետատվյալներում և կամրջի ֆյուժնի հաշվիչներում։ Լռելյայն Video Bridge ուղին չի կանչում խոսքի-տեքստի փոխակերպում կամ երկրորդ մեդիա պատճեն չի ներբեռնում. առանց այդ հստակ հետքի, այն մնում է միայն տեսանյութ։

Տեքստի պահպանում (#12150 P1)։ Սա ավտոմատ կերպով կիրառվում է, երբ Video Bridge-ը (ինքնին ընտրովի) ցուցադրում է տեքստի հուշում. առանձին պահպանման դրոշ չկա։ Երբ հարցումը ցուցադրում է որևէ տեքստի հուշում (զանգահարողի կողմից հայտարարված transcript կամ միաձուլված audioTranscript), պաշտպանիչը նշում է այն videoBridgeObserved և ստեղծում է տեսանյութի նկարագրության խմբագրված ստվեր՝ նույնական ցուցադրում, որում յուրաքանչյուր հուշման ազատ տեքստային մարմինը փոխարինվում է [redacted-video-transcript]-ով, որը ստեղծվում է կառուցվածքային հուշման դաշտը փոխարինելով նախքան տողի հավաքումը (երբեք հարթեցված տեքստը վերլուծելով, այնպես որ ոչ մի հուշման բովանդակություն՝ թշնամական կամ սովորական, ներառյալ ] պարունակող մարմինները, ինչպիսիք են [անլսելի]/[երաժշտություն]-ը, չի կարող պահպանվել)։ Պահպանված զանգի մատյանի հարցման մարմինը յուրաքանչյուր տեսանյութից ստացված տեքստային մասը փոխարինում է այդ խմբագրված ստվերով, որը համընկնում է բովանդակության հավասարությամբ. fullText խարիսխը նորից կարդացվում է ավարտված նախնական զանգի պաշտպանիչի բեռնվածքից, այնպես որ համընկնումը դեռևս հաջողվում է ավելի ուշ շղթայական պաշտպանիչներից հետո (PII և հավատարմագրերի դիմակները, առաջնահերթություններ 10/95) վերաշարադրում են նկարագրության տեքստը տեղում և համակարգի հուշման/հանձնման/հիշողության ներարկումից հետո վերաձևում են հաղորդագրությունների զանգվածը։ Մոդելին ուղարկված մարմինը մնում է անփոփոխ։ Դիտարկված հարցումը նաև չի լրացնում որևէ կայուն հիշողություն (ինչպես հարցումից, այնպես էլ պատասխանից ստացված արդյունահանումը բաց է թողնվում), այնպես որ մոդելի սեփական պատասխանը չի կարող տեքստի տեքստը արձագանքել հիշողության մեջ։

Լրացուցիչ պահպանված պատճենները օգտագործում են նույն դիտարկված-հարցման ազդանշանը։ Հում նախնական-պաշտպանիչի հաճախորդի-հարցման լուսանկարը, հիշողության մեջ սպասող հարցումը և վաղ մերժված-հարցման մատյանը կառուցվածքորեն փոխարինում են տեքստի դաշտերը տեսանյութի մասերում. խողովակաշարի փուլերի կողմից սինթեզված տողային հուշումները և կոնտեքստի հանձնումը խմբագրվում են պահպանված-հարցման-մարմնի ընդունիչում։ Պահպանված video_content_removed նշիչը previous_response_id շարունակությունը ստիպում է ձախողվել փակ վիճակում, այլ ոչ թե վերակառուցել տեքստը, որը միտումնավոր դեն էր նետվել։ Եթե դիտարկված հարցումը կորցնում է իր մասնակի խմբագրման ստվերը մինչև մուտքագրումը, կամ նույնիսկ մի քանի տեսանյութի ստվերներից մեկը չի համընկնում ավելի ուշ հարցման մուտացիաներից հետո, պահպանված հարցման մարմինը ամբողջությամբ բաց է թողնվում՝ մասնակիորեն խմբագրված տեքստը պահպանելու փոխարեն։

Դիտարկված հարցման համար մոդելի պատասխանը կարող է մեջբերել տեքստի ցանկացած մաս՝ առանց կառուցվածքային հուշման սահմանի։ Դրա պահպանված զանգի մատյանի responseBody-ն, հետևաբար, փոխարինվում է բացթողման նշիչով. մանրամասն խողովակաշարի արտեֆակտը (որը կարող է ներառել վերին հոսանքի/հաճախորդի մարմինները և հոսքի կտորները) չի պահպանվում։ Սեմանտիկ, իդեմպոտենտության և դատողության-վերարտադրման քեշերը շրջանցում են այդ հարցման համար կարդալը և գրելը։ Պրովայդերի հարցումը և հաճախորդի համար տեսանելի պատասխանը մնում են անփոփոխ։ Վաղ keepalive բայթերը դատարկվում են ժամանակավոր բուֆերից, երբ մանրամասն արտեֆակտը բաց է թողնվում։ Կիրոյի սխալ ձևավորված EventStream նախազգուշացումը հաղորդում է միայն բեռնվածքի բայթերի քանակը, երբեք դրա բովանդակությունը կամ JSON վերլուծիչի հում սխալը։ Սա չի պնդում, որ յուրաքանչյուր անկապ պրովայդերի/պլագինի ախտորոշում ստուգվել է. ավելի լայն պահպանված-ընդունիչի մաքրումը հետևվում է #11658-ում։

Ներքին /api/modality-bridge/video/drilldown կյանքի ցիկլը առանձին, loopback/token-ով վավերացված քեշի ենթաշերտ է։ Յուրաքանչյուր գործողություն պահանջում է նաև կանոնական անթափանց հիմնական ID։ Նախքան արտադրական զանգահարողի միացումը, այն պետք է ստանա այդ ID-ն վավերացված վարձակալից և երբեք չպետք է փոխանցի հաճախորդի կողմից ընտրված արժեք։ Քեշի բանալիները այդ հիմնականը կապում են կանոնական նիստի և տեսանյութի հղման ID-ների հետ, պահում են միայն դրանց SHA-256-ից ստացված բանալիները և սահմանափակում են ինչպես կարդալը, այնպես էլ ջնջելը նույն հիմնականով։ Քեշը պահում է առավելագույնը 16 ստացված JPEG կադր յուրաքանչյուր մուտքի համար, դրանք ժամկետանց է դարձնում տասը րոպեից հետո և աջակցում է սահմանափակ start/end կարդալուն կամ նիստի հստակ ջնջմանը։

Յուրաքանչյուր հիմնական սահմանափակված է 16 մուտքով և 64 ՄԲ կանոնական JPEG տվյալներով։ Այդ սահմանները անկախ են գլոբալ 64 մուտքի/256 ՄԲ առաստաղից. հիմնական քվոտայի ճնշումը դուրս է մղում միայն այդ հիմնականի ամենաքիչ օգտագործված մուտքերը, նախքան գլոբալ LRU դուրս մղումը դիտարկվելը։ Ժամկետանց մուտքերը մաքրվում են ինչպես հիմնական, այնպես էլ գլոբալ հաշվառումից քեշի ակտիվության ժամանակ, մինչդեռ չեղարկումը և վավերացման ձախողումը մասնակի փոխարինում չեն կատարում։

Քեշը մերժում է ոչ կանոնական Base64-ը, ավելորդ լրացումները, ոչ JPEG մեդիան, սխալ ձևավորված կամ կտրված JPEG-ները և JPEG-ները, որոնք նախազգուշացում են առաջացնում սահմանափակ ամբողջական պատկերի sharp ապակոդավորման ժամանակ։ Այն վերակոդավորում է յուրաքանչյուր ընդունված պատկեր որպես կանոնական JPEG, լայնությունը և բարձրությունը ստանում է ապակոդավորված բայթերից՝ զանգահարողի դաշտերին վստահելու փոխարեն, և դեն է նետում ցանկացած հետևի բազմալեզու բայթեր՝ դրանք պահպանելու փոխարեն։ Միայն սահմանափակ կանոնական սեղմված բուֆերն է գանձվում երկու քվոտաներից։ JSON լարի սահմանը ներառում է Base64-ի ծախսերը 32 ՄԲ ապակոդավորված-մուտքի առաստաղի համար։ Յուրաքանչյուր պահպանված ստացում գրանցում է իր վավերացված JPEG ձևաչափը/լուծաչափը, նմուշառման քաղաքականությունը, ստացման տարբերակը, ստեղծման ժամանակը, սերվերի կողմից հաշվարկված բովանդակության հեշը և հեշավորված ծնողի հղումը, ինչպես նաև վստահելի զանգահարողի ծնողի-բովանդակության հեշը։ Չեղարկումը ստուգվում է ասինխրոն ապակոդավորման/հեշի փուլերի միջև՝ մինչև ատոմային քեշի հանձնումը։

Այս տրանշը դեռևս արտադրական պրոդյուսեր չի միացնում երթուղուն և չի ապահովում բազմաբնույթ տարբերակների ընտրություն: Թափանցիկ Video Bridge հարցումը ճանապարհը, հետևաբար, լրացուցիչ աշխատանք չի պահանջում, մինչդեռ վարձակալին կապված հիմնական ածանցումը և ամբողջական FU-08 բազմաբնույթ կյանքի ցիկլը մնում են հստակ հետագա աշխատանք, քան փաստաթղթավորված է որպես ամբողջական վարքագիծ:

Շրջանակները հաջորդաբար ենթագրվում են կազմաձևված Video մոդելով: Դատարկ Video վերագրումը ժառանգում է Vision կարգավորումը. եթե երկուսն էլ դատարկ են, Vision ավտոմատ երթուղիչը ընտրում է արդյունավետ տեսողական հնարավորություններ ունեցող մոդելը: Հաջող ենթագրերը փոխարինում են բնօրինակ մասը կայուն [Video description: նախածանցով, որը նաև նշում է տեքստը որպես անվստահելի մեդիայից ստացված դիտարկում և հրահանգում է ներքևի մոդելներին չհետևել մեդիայում հայտնաբերված հրահանգներին: Շրջանակ-ենթագիր քեշի բանալիները ներառում են JPEG բայթերը, հուշումը, ժամանակի դրոշմը և արդյունավետ մոդելը. միայն հաջող ենթագրերը քեշավորվում են: Քեշի գրառումները պահպանում են իրական հաջող պրոդյուսեր մոդելը, ներառյալ պահեստային մոդելը. կամուրջը հաղորդում է mixed, երբ տարբեր շրջանակներ արտադրվել են տարբեր մոդելներով: Քեշի հիթը վերաօգտագործում է այդ պրոդյուսերի ինքնությունը փոխարենը այն վերանշելու որպես պահանջվող երթուղային պլան: Ամբողջական տեսանյութի արդյունքի քեշը բանալի է դրվում յուրաքանչյուր մուտքի վրա, որը փոխում է ելքը՝ հուշումը, արդյունավետ մոդելը, նմուշառման քաղաքականությունը, շրջանակների քանակը, իմաստային վերլուծության ռեժիմը, SHA-256 նորմալացված ֆոկուսի հուշման մատնահետքը, ֆոկուսի պատուհանը, transcript, audioTranscript և կոնտակտային թերթիկի դրոշը, այնպես որ այդ չափումներից որևէ մեկի փոփոխությունը քեշի բացթողում է, երբեք հնացած վերաօգտագործում: Տեսողական կրկնօրինակման քաղաքականության տարբերակը, շեմը և սահմանափակված թեկնածու-շրջանակների քանակը նույնպես հստակ են արդյունքի-քեշի բանալիում և մետատվյալներում. քաղաքականության փոփոխությունը, հետևաբար, չի կարող վերաօգտագործել հնացած ամբողջական տեսանյութի նկարագրությունը: Արդյունքի-քեշի v4 մետատվյալները պահպանում են ռեժիմը և մատնահետքը, երբեք հում օգտատիրոջ առաջադրանքը: Guardrail մետատվյալները հաղորդում են ինչպես պահանջվող, այնպես էլ արդյունավետ վերլուծության ռեժիմները. պահանջվող focused ռեժիմը առանց օգտագործելի օգտատիրոջ տեքստի հաղորդվում է որպես արդյունավետ full:

Պաշտպանիչը արդյունահանում է յուրաքանչյուր աջակցվող տեսանյութի մաս, բայց նկարագրում է ոչ ավելի, քան modalityBridgeVideoMaxVideos: Նպատակի համար, որը ապացուցված է, որ ունի supportsVideo === false, ձախողված և սահմանը գերազանցող տեսանյութերը դառնում են հստակ անվտանգ տեքստային մարկերներ, այնպես որ ոչ մի հում տեսանյութ չի պահպանվում: Երբ հնարավորությունը անհայտ է, այդ մասերը մնում են անձեռնմխելի: supportsVideo === true ունեցող նպատակները շրջանցում են կամուրջը: Հաճախորդի հարցման ընդհատման ազդանշանը տարածվում է ներբեռնման, բրոքերի հերթի, ենթապրոցեսների և ենթագրերի կանչերի միջոցով. ընդհատումները դադարում են տեսանյութերի միջև և երբեք չեն ձախողվում բաց մինչև հում մեդիա:

Գործարկման կարգավորումները DB-ի կողմից ապահովված են և Zod-ով վավերացված.

Բանալի Լռակայուն Միջակայք / վարքագիծ
modalityBridgeVideoEnabled false Ընտրովի գործարկում, ընտրովի
modalityBridgeVideoAnalysisMode "full" full պահպանում է ընդհանուր ենթագրերը. focused օգտագործում է սահմանափակ, անվստահելի վերջին օգտատիրոջ համատեքստ
modalityBridgeVideoModel "" Ժառանգել Vision Bridge մոդելը
modalityBridgeVideoFrameCount 8 1–16
modalityBridgeVideoSamplingPolicy "uniform" uniform, scene_aware, կամ համաչափ segment_aware. դետեկտորի ձախողումը վերադառնում է uniform
modalityBridgeVideoMaxVideos 1 1–4
modalityBridgeVideoTimeout 120000 1000–120000 մվ

Ժառանգական պահպանված Video ժամանակի սահմանաչափի արժեքները 120 վայրկյանից բարձր սահմանափակվում են բրոքերի վերջնաժամկետով. այդ սահմանից բարձր նոր կարգավորումների գրառումները մերժվում են: GET /api/modality-bridge/video/runtime պահանջում է վստահելի դրոշմված loopback տեղայնություն մինչև նույնականացումը կամ գործարկման ստուգումը, այնուհետև պահանջում է կառավարման նույնականացում: Այն վերադարձնում է միայն available, մաքրված FFmpeg/ffprobe տարբերակները և ֆիքսված պատճառ, երբ գործարկումը անհասանելի է: Ներքին արդյունահանման վերջնակետը հանրային վերբեռնման API չէ. հերթի հագեցվածությունը վերադարձնում է 503 գումարած Retry-After, զանգողի անջատումը վերադարձնում է 499, իսկ ֆիքսված բրոքերի վերջնաժամկետը վերադարձնում է 504: Փոխակերպված պատասխանները ավելացնում են video->text;model=<visionModel>;parts=<videos> կենտրոնական x-omniroute-modality-bridge վերնագրին՝ առանց Vision կամ Audio հատվածները հեռացնելու:

PII Masker (piiMasker.ts)

Աշխատում է երկու փուլերում:

  • preCall կլոնավորում է բեռնվածքը, անցնում է system, messages, input և prompt (ներառյալ պարզ տողային տարրերը) և կիրառում է processPII() ( @/shared/utils/inputSanitizer-ից) տողային content/text դաշտերին: Երբ PII_REDACTION_ENABLED=true, հայտնաբերված PII-ը խմբագրվում է ելքային բեռնվածքում: Սա անկախ է INPUT_SANITIZER_MODE-ից (որը միայն վերահսկում է հուշման ներարկման քաղաքականությունը): Երբ խմբագրումն անջատված է, կանչը գրանցում է հայտնաբերման քանակները՝ առանց բովանդակությունը վերագրելու:
  • postCall խորը կլոնավորում է պատասխանը, գործարկում է sanitizePIIResponse() գումարած Responses-API-ի ձևի դիմակը (maskResponsesOutput — ընդգրկում է output_text և output[].content[].text): Եթե որևէ խմբագրում տեղի է ունենում, փոփոխված պատասխանը փոխարինում է բնօրինակը:

Պաշտպանիչը երբեք չի արգելափակում. այն միայն ծանոթագրում է (meta.detections, meta.redacted) կամ վերագրում:

Հուշման ներարկում (promptInjection.ts)

Հայտնաբերում է հակառակորդի կառուցվածքները օգտատիրոջ կողմից տրամադրված բովանդակության մեջ և կիրառում է կազմաձևված քաղաքականությունը: Վարքագիծը պայմանավորված է միջավայրի փոփոխականներով և կոնստրուկտորի ընտրանքներով:

Կարգավորում Միջավայրի փոփոխական Լռելյայն Ազդեցություն
Միացված է INPUT_SANITIZER_ENABLED true Երբ false է, պաշտպանիչը կարճ միացում է կատարում:
Ռեժիմ INJECTION_GUARD_MODE / INPUT_SANITIZER_MODE warn Ներարկման քաղաքականություն՝ block, warn կամ log: (redact-ը ընդունվում է հետադարձ համատեղելիության համար, բայց չի հեռացնում ներարկման տեքստը. PII վերաշարադրման հարցումը վերահսկվում է PII_REDACTION_ENABLED-ով:)
Արգելափակման շեմ blockThreshold տարբերակ / INPUT_SANITIZER_BLOCK_THRESHOLD (փոխարինող INJECTION_GUARD_BLOCK_THRESHOLD) high Արգելափակելու համար պահանջվող նվազագույն ծանրություն: Միջինը լռելյայն դիտարկման ռեժիմում է:

Ռեժիմի առաջնահերթություն (getMode): կանչողի options.mode → INJECTION_GUARD_MODE DB ֆունկցիոնալության դրոշի վերասահմանում (Dashboard → Settings → Feature Flags) → INJECTION_GUARD_MODE միջավայր → INPUT_SANITIZER_MODE միջավայր → warn: Հետևաբար, վահանակի վերասահմանումը գերակայում է միջավայրի փոփոխականներին, այնպես որ Feature Flags UI-ն վերահսկում է գործող պաշտպանիչը կենդանի ռեժիմում (առանց վերագործարկման): DB-ի ընթերցումը անվտանգ է. եթե այն սխալ է տալիս, պաշտպանիչը վերադառնում է միջավայրի վրա հիմնված վարքագծին, և երբ վերասահմանում չի սահմանվում, վարքագիծը նույնական է միայն միջավայրի լուծմանը:

Հայտնաբերման աղբյուրներ.

  1. sanitizeRequest() @/shared/utils/inputSanitizer-ից (ընդհանուր դետեկտորի հավաքածու, որն օգտագործվում է խողովակաշարի այլ մասերում):
  2. Ներկառուցված DEFAULT_GUARD_PATTERNS (ներկայումս system_override_inline և markdown_system_block, երկուսն էլ high ծանրության):
  3. Ընտրովի customPatterns, որոնք փոխանցվում են կոնստրուկտորի ընտրանքների միջոցով (տողեր, regex, կամ { name, pattern, severity } գրառումներ):

Երբ mode === "block" և առնվազն մեկ հայտնաբերում համապատասխանում է ծանրության շեմին, preCall-ը վերադարձնում է { block: true, message: "Request rejected: suspicious content detected" }: warn/log ռեժիմներում պաշտպանիչը գրանցում է, բայց թույլ է տալիս կանչը: Ընդհանուր օգնական evaluatePromptInjection()-ը նույնպես արտահանվում է այն կանչողների համար, ովքեր պետք է գնահատեն հուշումները՝ առանց ռեգիստրի միջով անցնելու:

Սկանավորման սահման (v3.8.20). դետեկտորը ստուգում է միայն միացված հուշման տեքստի առաջին 16 ԿԲ-ը՝ MAX_INJECTION_SCAN_BYTES = 16 * 1024 (16 384 բայթ) src/shared/utils/inputSanitizer.ts-ում: Ե՛վ detectInjection(), և՛ evaluatePromptInjection() slice(0, MAX_INJECTION_SCAN_BYTES) նախքան օրինաչափության ցիկլը գործարկելը: Ներարկման հրահանգները գտնվում են մուտքի վերին մասում, այնպես որ սա սահմանափակում է regex CPU/GC-ն բազմահարյուր ԿԲ բեռնվածքների վրա՝ առանց հայտնաբերումը թուլացնելու (տես #3932, #4041):

Հավատարմագրերի դիմակավորող (credentialMasker.ts)

Գործարկվում է երկու փուլերում, լռելյայն շղթայում վերջինը (առաջնահերթություն 95): Դիմակավորում է հայտնի API-բանալիների / գաղտնի թոքենների օրինաչափությունները ելքային բեռնվածքից (հաղորդագրության բովանդակություն, գործիքի կանչի արգումենտներ, գործիքի արդյունքներ) և մատակարարի պատասխանից, այնպես որ հուշման մեջ տեղադրված հավատարմագիրը (կամ գործիքի արդյունքի կողմից արտացոլվածը) չի արտահոսում վերին մատակարարին կամ հետ չի վերադառնում հաճախորդին:

  • Միայն ընտրովի, նույն կոնվենցիան, ինչ PII դիմակավորումը (Կոշտ կանոն #20-ին մոտ). անջատված է, եթե settings.credentialRedactionEnabled === true կամ CREDENTIAL_REDACTION_ENABLED=true: Եթե այն անջատված է, պաշտպանիչը անգործուն է. այն երբեք չի արգելափակում և երբեք չի վերաշարադրում:
  • redactCredentials()-ը քայլում է ամբողջ բեռնվածքի/պատասխանի ծառով (walkValue(), պրոտոտիպ-աղտոտումից անվտանգ, ցիկլից անվտանգ WeakSet-ի միջոցով) և փոխարինում է համընկնումները [REDACTED:<type>] տեղապահով՝ կլոնավորելով միայն այն ճյուղերը, որոնք իրականում փոխվել են:
  • CREDENTIAL_PATTERNS-ը ներառում է LLM մատակարարի բանալիներ (OpenAI, OpenAI-proj, Anthropic, Google, Hugging Face, Replicate), VCS/SaaS թոքեններ (GitHub, Slack, Linear, Notion, npm, Postman, Discord), վճարման բանալիներ (Stripe, Square), ամպային բանալիներ (AWS մուտքի բանալի, Twilio, SendGrid, Mailgun), անձնական բանալիներ / JWT-ներ, հավատարմագիր պարունակող կապի տողեր (mongodb://user:pass@..., և այլն), և ընդհանուր Authorization/x-api-key/api-key/apikey վերնագրի-արժեքի օրինաչափություն: Վերնագրի տեսք ունեցող բանալիները (authorization, x-api-key, api-key, apikey) դիմակավորվում են կառուցվածքորեն (միայն արժեքը, սխեմայի նախածանցը, ինչպիսին է Bearer /Basic , պահպանվում է), այլ ոչ թե ընդհանուր տեքստային regex-ի միջոցով:
  • Պաշտպանիչը երբեք չի արգելափակում. այն միայն վերաշարադրում է (modifiedPayload / modifiedResponse) և ծանոթագրում է (meta.credentialsRedacted, meta.count):

Ռեգրեսիայի պաշտպանություն՝ 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;
}

Պաշտպանիչ սահմանափակումը ազդարարում է «փոփոխություն չկա»՝ վերադարձնելով կա՛մ void, կա՛մ {}, կա՛մ { block: false }։ modifiedPayload/modifiedResponse վերադարձնելը փոխարինում է շղթայով դեպի հաջորդ պաշտպանիչ սահմանափակումներ փոխանցվող արժեքը։ signal?: AbortSignal-ը կանչողի կենսացիկլը փոխանցում է պաշտպանիչ սահմանափակումներին։ Հարցման ընդհատումը կանխամտածված fail-open բացառություն է․ մեդիա կամուրջները դադարեցնում են աշխատանքը և մաքրում ռեսուրսները՝ առանց չմշակված մեդիան վերականգնելու այն թիրախի համար, որը, ինչպես հայտնի է, չի աջակցում այն։

Ռեեստր (registry.ts)

guardrailRegistry եզակի օրինակը տրամադրում է՝

  • register(guardrail) — ավելացնում է պաշտպանիչ սահմանափակում (կամ փոխարինում է այն ըստ նորմալացված անվան) և վերադասավորում ըստ աճող priority-ի։
  • clear() / list() — վարչական օժանդակ մեթոդներ։
  • runPreCallHooks(payload, context) — հերթով մշակում է ակտիվ պաշտպանիչ սահմանափակումները, փոխանցում է payload-ը modifiedPayload-ի միջոցով և կանգ է առնում առաջին block: true-ի դեպքում։
  • runPostCallHooks(response, context) — նույն հոսքը պատասխանի կողմում։
  • resetGuardrailsForTests({ registerDefaults }) — մաքրում է վիճակը և, ըստ անհրաժեշտության, վերագրանցում է լռելյայնները՝ թեստերի մաքուր մեկուսացման համար։

Երկու գործարկիչներն էլ վերադարձնում են { blocked, payload|response, results, guardrail?, message? }, որտեղ results-ը GuardrailExecutionResult գրառումների զանգված է, որոնք ներառում են յուրաքանչյուր պաշտպանիչ սահմանափակման blocked, skipped, modified, error և meta դաշտերը, որոնք օգտակար են հետագծման համար։

Յուրաքանչյուր հարցման համար պաշտպանիչ սահմանափակումների անջատում

resolveDisabledGuardrails({ apiKeyInfo, body, headers })-ը հավաքում է պաշտպանիչ սահմանափակումների անունների կրկնազերծված ցանկ, որոնք պետք է բաց թողնվեն ընթացիկ հարցման համար։ Աղբյուրները (բոլորն ընտրովի են, բոլորը միավորվում են)՝

  • apiKeyInfo.disabledGuardrails
  • Հարցման մարմնի disabledGuardrails (վերին մակարդակում)
  • Հարցման մարմնի metadata.disabledGuardrails
  • x-omniroute-disabled-guardrails վերնագիր (կամ հին x-disabled-guardrails)

Արժեքները կարող են լինել տողերի զանգվածներ կամ ստորակետերով բաժանված տող․ անունները նորմալացվում են փոքրատառ kebab-case ձևաչափի (pii_masker → pii-masker)։ Արդյունքը context.disabledGuardrails-ի միջոցով փոխանցվում է ռեեստրին, որը բաց է թողնում համապատասխան պաշտպանիչ սահմանափակումները (skipped: true՝ results-ում)։

Կատարման հերթականություն

src/sse/handlers/chat.ts-ով և open-sse/handlers/chatCore.ts-ով անցնող յուրաքանչյուր հարցման համար՝

  1. resolveDisabledGuardrails(...)-ը API բանալիից, հարցման մարմնից և վերնագրերից կազմում է բաց թողնման ցանկը։
  2. guardrailRegistry.runPreCallHooks(body, ctx)-ը պաշտպանիչ սահմանափակումները գործարկում է առաջնահերթության աճման կարգով՝
    • Անջատված պաշտպանիչ սահմանափակումներն արձանագրվում են որպես skipped։
    • Յուրաքանչյուր պաշտպանիչ սահմանափակման preCall-ը կարող է վերագրել օգտակար բեռը՝ օգտագործելով modifiedPayload։
    • Առաջին block: true-ն անմիջապես ընդհատում է շղթան, և մշակիչը վերադարձնում է պաշտպանիչ սահմանափակման մերժման պատասխան։
  3. Հնարավոր վերագրված օգտակար բեռը փոխանցվում է համակցված երթուղավորմանը և վերին հոսքի ուղարկմանը։
  4. Պատասխանը կազմելուց հետո guardrailRegistry.runPostCallHooks(...)-ը պատասխանի վրա գործարկում է նույն շղթան։ Այստեղ block: true-ն հեռացնում է վերին հոսքի պատասխանը։

Սխալ արձակող պաշտպանիչ սահմանափակումներն արձանագրվում են error: <message>-ով և գրանցվում logger.warn-ի միջոցով, սակայն շղթան շարունակվում է. նախագծմամբ կիրառվում է սխալի դեպքում թույլատրելու մոտեցումը։

Կազմաձևում

Ներկառուցված պաշտպանիչ սահմանափակումների կողմից ընթերցվող միջավայրի փոփոխականները՝

Փոփոխական Օգտագործվում է Ազդեցություն
INPUT_SANITIZER_ENABLED prompt-injection Հայտնաբերումն ամբողջությամբ անջատելու համար սահմանեք false։
INPUT_SANITIZER_MODE prompt-injection Ներարկման քաղաքականությունը՝ warn, block կամ log։ Հնացած redact արժեքը չի վերագրում ներարկման տեքստը։
INJECTION_GUARD_MODE prompt-injection Ներարկման պաշտպանիչի ռեժիմը. նաև ՏԲ-ի գործառույթի դրոշակ է, որը գերակայում է միջավայրի փոփոխականների նկատմամբ (DB > ENV)։
INPUT_SANITIZER_BLOCK_THRESHOLD prompt-injection Նվազագույն խստությունը, որը մերժվում է MODE=block-ի դեպքում՝ high (լռելյայն), medium կամ low։
INJECTION_GUARD_BLOCK_THRESHOLD prompt-injection INPUT_SANITIZER_BLOCK_THRESHOLD-ի հնացած այլանունը։
PII_REDACTION_ENABLED pii-masker Երբ true է, հարցման PII-ը քողարկվում է՝ անկախ ներարկման ռեժիմից։
PII_RESPONSE_SANITIZATION / _MODE pii-masker (ներքևի հոսք) Կառավարում է պատասխանի կողմում քողարկիչի վարքագիծը։

Մոդալության կամրջի պաշտպանիչ սահմանափակումները կատարման ժամանակի կազմաձևումն ընթերցում են ՏԲ-ով ապահովվող կարգավորումների պահոցից (getSettings()), ոչ թե միջավայրի փոփոխականներից։ Պատկերի մշակման հիմնական բանալիներն են՝ modalityBridgeVisionEnabled, modalityBridgeVisionMode, modalityBridgeVisionModel, modalityBridgeVisionTaskAware, modalityBridgeVisionPrompt, modalityBridgeVisionTimeout, modalityBridgeVisionMaxImages, modalityBridgeVisionMaxChars, modalityBridgeCacheEnabled, modalityBridgeCacheTtlMinutes և modalityBridgeCacheMaxEntries։ Հնացած visionBridge* բանալիներն ընդունվում են միայն որպես փաստաթղթավորված՝ մեկ ցիկլի ընթերցման պահուստային տարբերակ. կառավարման վահանակից գրանցումները կիրառում են հիմնական բանալիները։ Լռելյայն արժեքները և պահուստային լուծիչը գտնվում են src/shared/constants/modalityBridgeDefaults.ts-ում, իսկ հնացած հաստատունները պահպանվում են src/shared/constants/visionBridgeDefaults.ts-ում։

Ձայնի մշակումն օգտագործում է modalityBridgeAudioEnabled, modalityBridgeAudioModel, modalityBridgeAudioTimeout և modalityBridgeAudioMaxClips, ինչպես նաև ընդհանուր modalityBridgeCache* կարգավորումները։ Ձայնի մշակման համար հնացած բանալիների պահուստային տարբերակ չկա, քանի որ այս բանալիները ներդրվել են Մոդալության կամրջի սխեմայի հետ։

Տեսանյութի մշակումն օգտագործում է modalityBridgeVideoEnabled, modalityBridgeVideoAnalysisMode, modalityBridgeVideoModel, modalityBridgeVideoFrameCount, modalityBridgeVideoSamplingPolicy, modalityBridgeVideoMaxVideos և modalityBridgeVideoTimeout, ինչպես նաև ընդհանուր modalityBridgeCache* կարգավորումները։ Այն լռելյայն անջատված է, քանի որ FFmpeg/ffprobe-ը ոչ պարտադիր գործառնական կախվածություններ են, իսկ կադրերի նկարագրությունների ստեղծումն ավելացնում է ուշացումն ու մոդելի օգտագործման արժեքը։

Հատուկ պաշտպանիչ կանոններ

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. Կամ գրանցեք ներմուծման պահին (registerDefaultGuardrails-ից ավելացնելով), կամ գործարկման ընթացքում կանչեք guardrailRegistry.register(...)-ը․ ռեեստրը փոխարինում է նույն նորմալացված անունն ունեցող ցանկացած նախորդ պաշտպանիչ կանոն։
  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 }՝ դատարկ ռեեստրից սկսելու և միայն թեստավորվող պաշտպանիչ կանոնները գրանցելու համար։ Vision Bridge-ն աջակցում է կախվածությունների ներմուծմանը (deps.getSettings, deps.callVisionModel), իսկ Audio Bridge-ը տրամադրում է համարժեք միջերեսներ՝ կարգավորումների, հնարավորությունների, STT մոդելի ընտրության, հավատարմագրերի ստուգումների և տրանսկրիպցիայի համար։ Հետևաբար, թեստերը կարող են ստուգել երկու հոսքերն էլ՝ առանց DB-ի կամ ցանցային հասանելիության։

Տես նաև

  • src/lib/guardrails/ — իրականացումը
  • src/shared/utils/inputSanitizer.ts — ընդհանուր դետեկտորը, որն ապահովում է հուշման ներարկման հայտնաբերումը և PII-ի քողարկումը
  • src/shared/constants/visionBridgeDefaults.ts — Vision Bridge-ի լռելյայն արժեքները և հարկադիր կամրջման մոդելների ցանկը
  • src/shared/constants/modalityBridgeDefaults.ts — Vision/Audio-ի ընդհանուր գործարկման միջավայրի լռելյայն արժեքները
  • docs/architecture/RESILIENCE_GUIDE.md — ուղղահայաց շերտ (շղթայի անջատիչ, սպասման ժամանակահատվածներ)
  • docs/reference/ENVIRONMENT.md — միջավայրի փոփոխականների ամբողջական տեղեկատուն

Ներարկման պաշտպանիչ կանոնով երթուղիների ծածկույթ և red-team թեստավորում (Փուլ 8 · Բլոկ D)

Ներարկման պաշտպանիչ կանոնը (createInjectionGuard / withInjectionGuard) ընդգրկում է օգտատիրոջ հուշումներ ընդունող բոլոր երթուղիները։ Այն հաշվի է առնում INJECTION_GUARD_MODE-ը (լռելյայն՝ warn = միայն գրանցել մատյանում, block = վերադարձնում է HTTP 400 SECURITY_001)։

Տեսակ Երթուղիներ Լռելյայն ռեժիմ
Տեքստ (առկա) /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-ն ստուգում է, որ յուրաքանչյուր երթուղի արգելափակում է OWASP-LLM կորպուսը INJECTION_GUARD_MODE=block ռեժիմում, իսկ garak-ը կատարում է ստուգումներ (գաղտնիքի բացակայության դեպքում՝ բաց է թողնում)։ moderations-ը ներառված է հետևողականության համար․ արգելափակման ռեժիմն օգտագործող օպերատորները կարող են այն բացառել resolveDisabledGuardrails-ի միջոցով։

Գիշերային աշխատանքային հոսքը (.github/workflows/nightly-llm-security.yml, cron + ձեռքով գործարկում) ունի երկու առաջադրանք՝

  • promptfoo-guard (արգելափակող) — գործարկում է promptfoo eval -c promptfooconfig.yaml-ը INJECTION_GUARD_MODE=block-ով։ Յուրաքանչյուր հակառակորդային դեպք (օրինակ՝ «անտեսիր բոլոր նախորդ հրահանգները…», DAN ոճի jailbreak-ներ) հաստատում է, որ պատասխանը պարունակում է error.code === "SECURITY_001", այսինքն՝ պաշտպանիչ կանոնն իսկապես մերժել է հարցումը։
  • garak (խորհրդատվական) — գործարկում է garak-ը --probes promptinject,dan,leakreplay-ով տեղային OmniRoute օրինակի (http://localhost:20128/v1) նկատմամբ։ Պայմանավորված է մատակարարի գաղտնիքի (PROMPTFOO_PROVIDER_KEY) առկայությամբ․ դրա բացակայության դեպքում առանց սխալի բաց է թողնվում և վերջում ունի || true, ուստի այն հաշվետվություն է ներկայացնում՝ առանց CI-ն ձախողելու։

Պաշտպանիչ օգնականի (createInjectionGuard / withInjectionGuard) ծածկույթը տարածվում է հուշում պարունակող յուրաքանչյուր /v1 երթուղու վրա․ հուշման տեքստը վերցվում է messages/input/prompt/query+documents/instructions/system դաշտերից՝ src/shared/utils/inputSanitizer.ts-ի extractMessageContents()-ի միջոցով։