[{"data":1,"prerenderedAt":980},["ShallowReactive",2],{"navigation_docs":3,"-docs-integration-guides-moderate-ai-agents":102,"-docs-integration-guides-moderate-ai-agents-surround":975},[4,8,12,16,20,24,28,32,36,40,44,82,86,90,94,98],{"title":5,"path":6,"stem":7},"Overview","\u002Fdocs","docs\u002Findex",{"title":9,"path":10,"stem":11},"Quickstart","\u002Fdocs\u002Fquickstart","docs\u002F01.quickstart",{"title":13,"path":14,"stem":15},"Authentication and keys","\u002Fdocs\u002Fauthentication","docs\u002F02.authentication",{"title":17,"path":18,"stem":19},"Images","\u002Fdocs\u002Fimages","docs\u002F03.images",{"title":21,"path":22,"stem":23},"Texts","\u002Fdocs\u002Ftexts","docs\u002F04.texts",{"title":25,"path":26,"stem":27},"Migrating from SightEngine","\u002Fdocs\u002Fmigrating-from-sightengine","docs\u002F05.migrating-from-sightengine",{"title":29,"path":30,"stem":31},"Workflows","\u002Fdocs\u002Fworkflows","docs\u002F06.workflows",{"title":33,"path":34,"stem":35},"Responses and errors","\u002Fdocs\u002Fresponses-and-errors","docs\u002F07.responses-and-errors",{"title":37,"path":38,"stem":39},"Limits and quotas","\u002Fdocs\u002Flimits-and-quotas","docs\u002F08.limits-and-quotas",{"title":41,"path":42,"stem":43},"The journal and ref","\u002Fdocs\u002Fjournal-and-ref","docs\u002F09.journal-and-ref",{"title":45,"path":46,"stem":47,"children":48,"page":81},"Integration guides","\u002Fdocs\u002Fintegration-guides","docs\u002F10.integration-guides",[49,53,57,61,65,69,73,77],{"title":50,"path":51,"stem":52},"Node.js and TypeScript","\u002Fdocs\u002Fintegration-guides\u002Fnodejs","docs\u002F10.integration-guides\u002F1.nodejs",{"title":54,"path":55,"stem":56},"Python","\u002Fdocs\u002Fintegration-guides\u002Fpython","docs\u002F10.integration-guides\u002F2.python",{"title":58,"path":59,"stem":60},"PHP","\u002Fdocs\u002Fintegration-guides\u002Fphp","docs\u002F10.integration-guides\u002F3.php",{"title":62,"path":63,"stem":64},"Go","\u002Fdocs\u002Fintegration-guides\u002Fgo","docs\u002F10.integration-guides\u002F4.go",{"title":66,"path":67,"stem":68},"Supabase Edge Functions","\u002Fdocs\u002Fintegration-guides\u002Fsupabase-edge-functions","docs\u002F10.integration-guides\u002F5.supabase-edge-functions",{"title":70,"path":71,"stem":72},"Cloudflare Workers","\u002Fdocs\u002Fintegration-guides\u002Fcloudflare-workers","docs\u002F10.integration-guides\u002F6.cloudflare-workers",{"title":74,"path":75,"stem":76},"Nuxt and Next","\u002Fdocs\u002Fintegration-guides\u002Fnuxt-and-next","docs\u002F10.integration-guides\u002F7.nuxt-and-next",{"title":78,"path":79,"stem":80},"Moderate an AI agent","\u002Fdocs\u002Fintegration-guides\u002Fmoderate-ai-agents","docs\u002F10.integration-guides\u002F8.moderate-ai-agents",false,{"title":83,"path":84,"stem":85},"AI coding agents","\u002Fdocs\u002Fai-agents","docs\u002F11.ai-agents",{"title":87,"path":88,"stem":89},"Best practices","\u002Fdocs\u002Fbest-practices","docs\u002F12.best-practices",{"title":91,"path":92,"stem":93},"Privacy and data","\u002Fdocs\u002Fprivacy-and-data","docs\u002F13.privacy-and-data",{"title":95,"path":96,"stem":97},"API reference","\u002Fdocs\u002Fapi-reference","docs\u002F14.api-reference",{"title":99,"path":100,"stem":101},"Changelog","\u002Fdocs\u002Fchangelog","docs\u002F15.changelog",{"id":103,"title":78,"body":104,"description":967,"extension":968,"links":969,"meta":970,"navigation":231,"path":79,"seo":971,"stem":80,"__hash__":974},"docs\u002Fdocs\u002F10.integration-guides\u002F8.moderate-ai-agents.md",{"type":105,"value":106,"toc":957},"minimark",[107,116,121,166,169,173,176,752,767,774,778,800,807,811,825,829,904,909,913,919,923,933,937,953],[108,109,110,111,115],"p",{},"An AI agent reads content it did not write and produces content nobody has read yet. This guide shows where the two checks go, with the module of the ",[112,113,114],"a",{"href":51},"Node.js guide",". The calls are the same from any language.",[117,118,120],"h2",{"id":119},"what-to-check","What to check",[122,123,124,140],"table",{},[125,126,127],"thead",{},[128,129,130,134,137],"tr",{},[131,132,133],"th",{},"Side",[131,135,136],{},"What it is",[131,138,139],{},"When to check",[141,142,143,155],"tbody",{},[128,144,145,149,152],{},[146,147,148],"td",{},"Input",[146,150,151],{},"The messages and images a user sends the agent.",[146,153,154],{},"Before they reach the model or a tool.",[128,156,157,160,163],{},[146,158,159],{},"Output",[146,161,162],{},"The text and images the agent generates, and the tool results it reposts.",[146,164,165],{},"Before you publish or send them.",[108,167,168],{},"One image or one text is one check, whatever the number of categories it is checked against. A run that checks one input and one output is two checks.",[117,170,172],{"id":171},"the-two-calls","The two calls",[108,174,175],{},"Check the input, run the model, check the output. A check that cannot be made holds the content: it is never published unchecked.",[177,178,184],"pre",{"className":179,"code":180,"filename":181,"language":182,"meta":183,"style":183},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { checkText, ModerationError } from \".\u002Fmoderation\"\n\ntype Verdict = \"accept\" | \"review\" | \"reject\"\n\n\u002F\u002F A check that cannot be made is a \"review\": hold the content.\nasync function verdict(text: string, ref: string): Promise\u003CVerdict> {\n  try {\n    return (await checkText(text, ref, \"support_agent\")).action\n  } catch (error) {\n    \u002F\u002F The content cannot be accepted as it is: refuse it.\n    if (error instanceof ModerationError && [400, 413, 415].includes(error.status)) return \"reject\"\n    \u002F\u002F Anything else, a timeout included: hold it.\n    return \"review\"\n  }\n}\n\n\u002F\u002F model, refuse and holdForReview are yours.\nexport async function answer(run: { id: string }, message: string) {\n  \u002F\u002F Before the model: what the user sent.\n  if ((await verdict(message, `${run.id}:in`)) === \"reject\") return refuse(run)\n\n  const reply = await model.generate(message)\n\n  \u002F\u002F Before you publish: what the agent wrote.\n  if ((await verdict(reply, `${run.id}:out`)) !== \"accept\") return holdForReview(run, reply)\n  return reply\n}\n","agent.ts","ts","",[185,186,187,226,233,274,279,286,339,347,388,408,414,478,484,495,501,507,512,518,563,569,633,638,666,671,677,738,747],"code",{"__ignoreMap":183},[188,189,192,196,200,204,207,210,213,216,219,223],"span",{"class":190,"line":191},"line",1,[188,193,195],{"class":194},"s7zQu","import",[188,197,199],{"class":198},"sMK4o"," {",[188,201,203],{"class":202},"sTEyZ"," checkText",[188,205,206],{"class":198},",",[188,208,209],{"class":202}," ModerationError",[188,211,212],{"class":198}," }",[188,214,215],{"class":194}," from",[188,217,218],{"class":198}," \"",[188,220,222],{"class":221},"sfazB",".\u002Fmoderation",[188,224,225],{"class":198},"\"\n",[188,227,229],{"class":190,"line":228},2,[188,230,232],{"emptyLinePlaceholder":231},true,"\n",[188,234,236,240,244,247,249,252,255,258,260,263,265,267,269,272],{"class":190,"line":235},3,[188,237,239],{"class":238},"spNyl","type",[188,241,243],{"class":242},"sBMFI"," Verdict",[188,245,246],{"class":198}," =",[188,248,218],{"class":198},[188,250,251],{"class":221},"accept",[188,253,254],{"class":198},"\"",[188,256,257],{"class":198}," |",[188,259,218],{"class":198},[188,261,262],{"class":221},"review",[188,264,254],{"class":198},[188,266,257],{"class":198},[188,268,218],{"class":198},[188,270,271],{"class":221},"reject",[188,273,225],{"class":198},[188,275,277],{"class":190,"line":276},4,[188,278,232],{"emptyLinePlaceholder":231},[188,280,282],{"class":190,"line":281},5,[188,283,285],{"class":284},"sHwdD","\u002F\u002F A check that cannot be made is a \"review\": hold the content.\n",[188,287,289,292,295,299,302,306,309,312,314,317,319,321,324,327,330,333,336],{"class":190,"line":288},6,[188,290,291],{"class":238},"async",[188,293,294],{"class":238}," function",[188,296,298],{"class":297},"s2Zo4"," verdict",[188,300,301],{"class":198},"(",[188,303,305],{"class":304},"sHdIc","text",[188,307,308],{"class":198},":",[188,310,311],{"class":242}," string",[188,313,206],{"class":198},[188,315,316],{"class":304}," ref",[188,318,308],{"class":198},[188,320,311],{"class":242},[188,322,323],{"class":198},"):",[188,325,326],{"class":242}," Promise",[188,328,329],{"class":198},"\u003C",[188,331,332],{"class":242},"Verdict",[188,334,335],{"class":198},">",[188,337,338],{"class":198}," {\n",[188,340,342,345],{"class":190,"line":341},7,[188,343,344],{"class":194},"  try",[188,346,338],{"class":198},[188,348,350,353,357,360,362,364,366,368,370,372,374,377,379,382,385],{"class":190,"line":349},8,[188,351,352],{"class":194},"    return",[188,354,356],{"class":355},"swJcz"," (",[188,358,359],{"class":194},"await",[188,361,203],{"class":297},[188,363,301],{"class":355},[188,365,305],{"class":202},[188,367,206],{"class":198},[188,369,316],{"class":202},[188,371,206],{"class":198},[188,373,218],{"class":198},[188,375,376],{"class":221},"support_agent",[188,378,254],{"class":198},[188,380,381],{"class":355},"))",[188,383,384],{"class":198},".",[188,386,387],{"class":202},"action\n",[188,389,391,394,397,399,402,405],{"class":190,"line":390},9,[188,392,393],{"class":198},"  }",[188,395,396],{"class":194}," catch",[188,398,356],{"class":355},[188,400,401],{"class":202},"error",[188,403,404],{"class":355},") ",[188,406,407],{"class":198},"{\n",[188,409,411],{"class":190,"line":410},10,[188,412,413],{"class":284},"    \u002F\u002F The content cannot be accepted as it is: refuse it.\n",[188,415,417,420,422,424,427,429,432,435,439,441,444,446,449,452,454,457,459,461,463,466,469,472,474,476],{"class":190,"line":416},11,[188,418,419],{"class":194},"    if",[188,421,356],{"class":355},[188,423,401],{"class":202},[188,425,426],{"class":198}," instanceof",[188,428,209],{"class":242},[188,430,431],{"class":198}," &&",[188,433,434],{"class":355}," [",[188,436,438],{"class":437},"sbssI","400",[188,440,206],{"class":198},[188,442,443],{"class":437}," 413",[188,445,206],{"class":198},[188,447,448],{"class":437}," 415",[188,450,451],{"class":355},"]",[188,453,384],{"class":198},[188,455,456],{"class":297},"includes",[188,458,301],{"class":355},[188,460,401],{"class":202},[188,462,384],{"class":198},[188,464,465],{"class":202},"status",[188,467,468],{"class":355},")) ",[188,470,471],{"class":194},"return",[188,473,218],{"class":198},[188,475,271],{"class":221},[188,477,225],{"class":198},[188,479,481],{"class":190,"line":480},12,[188,482,483],{"class":284},"    \u002F\u002F Anything else, a timeout included: hold it.\n",[188,485,487,489,491,493],{"class":190,"line":486},13,[188,488,352],{"class":194},[188,490,218],{"class":198},[188,492,262],{"class":221},[188,494,225],{"class":198},[188,496,498],{"class":190,"line":497},14,[188,499,500],{"class":198},"  }\n",[188,502,504],{"class":190,"line":503},15,[188,505,506],{"class":198},"}\n",[188,508,510],{"class":190,"line":509},16,[188,511,232],{"emptyLinePlaceholder":231},[188,513,515],{"class":190,"line":514},17,[188,516,517],{"class":284},"\u002F\u002F model, refuse and holdForReview are yours.\n",[188,519,521,524,527,529,532,534,537,539,541,544,546,548,551,554,556,558,561],{"class":190,"line":520},18,[188,522,523],{"class":194},"export",[188,525,526],{"class":238}," async",[188,528,294],{"class":238},[188,530,531],{"class":297}," answer",[188,533,301],{"class":198},[188,535,536],{"class":304},"run",[188,538,308],{"class":198},[188,540,199],{"class":198},[188,542,543],{"class":355}," id",[188,545,308],{"class":198},[188,547,311],{"class":242},[188,549,550],{"class":198}," },",[188,552,553],{"class":304}," message",[188,555,308],{"class":198},[188,557,311],{"class":242},[188,559,560],{"class":198},")",[188,562,338],{"class":198},[188,564,566],{"class":190,"line":565},19,[188,567,568],{"class":284},"  \u002F\u002F Before the model: what the user sent.\n",[188,570,572,575,578,580,582,584,587,589,592,594,596,599,602,605,608,610,613,615,617,619,621,623,626,628,630],{"class":190,"line":571},20,[188,573,574],{"class":194},"  if",[188,576,577],{"class":355}," ((",[188,579,359],{"class":194},[188,581,298],{"class":297},[188,583,301],{"class":355},[188,585,586],{"class":202},"message",[188,588,206],{"class":198},[188,590,591],{"class":198}," `${",[188,593,536],{"class":202},[188,595,384],{"class":198},[188,597,598],{"class":202},"id",[188,600,601],{"class":198},"}",[188,603,604],{"class":221},":in",[188,606,607],{"class":198},"`",[188,609,468],{"class":355},[188,611,612],{"class":198},"===",[188,614,218],{"class":198},[188,616,271],{"class":221},[188,618,254],{"class":198},[188,620,404],{"class":355},[188,622,471],{"class":194},[188,624,625],{"class":297}," refuse",[188,627,301],{"class":355},[188,629,536],{"class":202},[188,631,632],{"class":355},")\n",[188,634,636],{"class":190,"line":635},21,[188,637,232],{"emptyLinePlaceholder":231},[188,639,641,644,647,649,652,655,657,660,662,664],{"class":190,"line":640},22,[188,642,643],{"class":238},"  const",[188,645,646],{"class":202}," reply",[188,648,246],{"class":198},[188,650,651],{"class":194}," await",[188,653,654],{"class":202}," model",[188,656,384],{"class":198},[188,658,659],{"class":297},"generate",[188,661,301],{"class":355},[188,663,586],{"class":202},[188,665,632],{"class":355},[188,667,669],{"class":190,"line":668},23,[188,670,232],{"emptyLinePlaceholder":231},[188,672,674],{"class":190,"line":673},24,[188,675,676],{"class":284},"  \u002F\u002F Before you publish: what the agent wrote.\n",[188,678,680,682,684,686,688,690,693,695,697,699,701,703,705,708,710,712,715,717,719,721,723,725,728,730,732,734,736],{"class":190,"line":679},25,[188,681,574],{"class":194},[188,683,577],{"class":355},[188,685,359],{"class":194},[188,687,298],{"class":297},[188,689,301],{"class":355},[188,691,692],{"class":202},"reply",[188,694,206],{"class":198},[188,696,591],{"class":198},[188,698,536],{"class":202},[188,700,384],{"class":198},[188,702,598],{"class":202},[188,704,601],{"class":198},[188,706,707],{"class":221},":out",[188,709,607],{"class":198},[188,711,468],{"class":355},[188,713,714],{"class":198},"!==",[188,716,218],{"class":198},[188,718,251],{"class":221},[188,720,254],{"class":198},[188,722,404],{"class":355},[188,724,471],{"class":194},[188,726,727],{"class":297}," holdForReview",[188,729,301],{"class":355},[188,731,536],{"class":202},[188,733,206],{"class":198},[188,735,646],{"class":202},[188,737,632],{"class":355},[188,739,741,744],{"class":190,"line":740},26,[188,742,743],{"class":194},"  return",[188,745,746],{"class":202}," reply\n",[188,748,750],{"class":190,"line":749},27,[188,751,506],{"class":198},[108,753,754,756,757,763,764,384],{},[185,755,376],{}," is a workflow you created in the ",[112,758,762],{"href":759,"rel":760},"https:\u002F\u002Fopenshield.dev\u002Fdashboard\u002Fworkflows",[761],"nofollow","dashboard",". Leave the third argument out to use ",[185,765,766],{},"default",[108,768,769,770,773],{},"For an image the agent received or generated, call ",[185,771,772],{},"checkImage"," the same way: the third argument is the workflow.",[117,775,777],{"id":776},"one-ref-per-step","One ref per step",[108,779,780,783,784,787,788,791,792,795,796,799],{},[185,781,782],{},"ref"," is your own id for the content, 1 to 128 characters with no control character. Use the run id and the step, such as ",[185,785,786],{},"run_8f3a:in"," and ",[185,789,790],{},"run_8f3a:out",". It comes back in the answer and stays in the ",[112,793,794],{"href":42},"journal",", so when a reply was held you filter the journal by the start of the ref (",[185,797,798],{},"run_8f3a",") and see the decision, the reasons with their scores and thresholds, and the workflow version. The content is never kept.",[801,802,803,804,806],"warning",{},"Do not put personal data in a ",[185,805,782],{},". Use an opaque id from your own database.",[117,808,810],{"id":809},"a-workflow-per-agent","A workflow per agent",[108,812,813,814,817,818,821,822,824],{},"A ",[112,815,816],{"href":30},"workflow"," decides which categories are checked and how strictly. Give a customer-facing agent a strict one and an internal tool a lenient one. Create one key for each agent, limit it to the workflow it needs and to images, texts or both: a call outside that gets ",[185,819,820],{},"403 forbidden",". ",[112,823,13],{"href":14}," explains scopes.",[117,826,828],{"id":827},"when-a-check-cannot-be-made","When a check cannot be made",[122,830,831,841],{},[125,832,833],{},[128,834,835,838],{},[131,836,837],{},"Answer",[131,839,840],{},"What to do",[141,842,843,863,876,893],{},[128,844,845,856],{},[146,846,847,849,850,849,853],{},[185,848,438],{},", ",[185,851,852],{},"413",[185,854,855],{},"415",[146,857,858,859,862],{},"The content cannot be accepted as it is: refuse it. For ",[185,860,861],{},"413 text_too_long",", see below.",[128,864,865,873],{},[146,866,867,849,870],{},[185,868,869],{},"401",[185,871,872],{},"403",[146,874,875],{},"A configuration problem. Log it, without the key, and alert your team.",[128,877,878,890],{},[146,879,880,849,883,886,887],{},[185,881,882],{},"429",[185,884,885],{},"503"," with ",[185,888,889],{},"Retry-After",[146,891,892],{},"Wait that many seconds and retry, at most twice.",[128,894,895,901],{},[146,896,897,900],{},[185,898,899],{},"500",", a timeout, a network error",[146,902,903],{},"Fail closed: hold the content.",[108,905,906,908],{},[112,907,33],{"href":34}," lists every type.",[117,910,912],{"id":911},"long-outputs","Long outputs",[108,914,915,916,918],{},"A text is at most 20,000 characters (5,000 on the free plan). A longer output gets ",[185,917,861],{},". Split it at paragraph boundaries and check each part: each part is one check.",[117,920,922],{"id":921},"keep-the-key-on-your-servers","Keep the key on your servers",[108,924,925,926,929,930,932],{},"The agent's runtime calls the API with a key. If the agent runs in a browser or on a user's device, it must call your own backend, which calls openshield: the API refuses requests that carry a browser ",[185,927,928],{},"Origin"," header. ",[112,931,87],{"href":88}," says more.",[117,934,936],{"id":935},"what-it-does-not-do","What it does not do",[938,939,940,944,947],"ul",{},[941,942,943],"li",{},"It checks images and text. It does not check video or audio.",[941,945,946],{},"It checks content against categories such as unsafe text, hate and personal data. It does not detect prompt injection.",[941,948,949,950,952],{},"Nobody reviews content for you. A ",[185,951,262],{}," decision goes back to your own team, and the content was never stored at openshield.",[954,955,956],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":183,"searchDepth":228,"depth":228,"links":958},[959,960,961,962,963,964,965,966],{"id":119,"depth":228,"text":120},{"id":171,"depth":228,"text":172},{"id":776,"depth":228,"text":777},{"id":809,"depth":228,"text":810},{"id":827,"depth":228,"text":828},{"id":911,"depth":228,"text":912},{"id":921,"depth":228,"text":922},{"id":935,"depth":228,"text":936},"Check what an agent reads and what it writes with two calls and a fallback, so nothing unchecked reaches the model or the reader.","md",null,{},{"title":972,"description":973},"Moderate AI agents and LLM output","Check what an AI agent reads and writes with two calls, the user's message before the model and the output before it is published, and one ref per run.","fVMCt-hBHu8ruo-6Gp11CY4WyvVdoWcybSEupMl-7dA",[976,978],{"title":74,"path":75,"stem":76,"description":977,"children":-1},"Moderate content in a Nuxt server route or a Next.js route handler, so the key never leaves the server.",{"title":83,"path":84,"stem":85,"description":979,"children":-1},"Hand the integration to your coding agent with a ready prompt, llms.txt and the OpenAPI document.",1792436179913]