{
  "aboutHtml": "<p>Gemini 3.8 Flash on tarkoitettu pitkäkestoisiin ohjelmistotekniikan tehtäviin, agenttiprosesseihin ja vaativaan tietotyöhön. Google kuvaa sitä Gemini 3.7 Flash -mallin jatkokehitykseksi, jossa painotetaan prosesseja, joiden ratkaisu ei pääty yhteen vastaukseen: malli palaa aineistoihin, käyttää työkaluja ja jatkaa vaiheketjua.</p><h4>Analysoitavat aineistot</h4><p>Google ilmoittaa syötteiksi <strong>tekstin, kuvat, videon, äänen ja PDF-tiedostot</strong>. Ailoot API:n nykyisessä luettelossa tekstimenetelmien syötteeksi ilmoitetaan <strong>teksti ja kuvat</strong> ja tulosteeksi teksti. Video, ääni ja PDF eivät kuulu tähän syötevalikoimaan. Syötteen raja on <strong>1 048 576 tokenia</strong> ja tulosteen <strong>65 536 tokenia</strong>. Malli muodostaa tekstituloksen, joka voi sisältää ohjelmakoodia ja rakenteista tietoa. Kuvien ja äänen luominen ei kuulu tämän nimenomaisen version ominaisuuksiin.</p><h4>Päättely ja työkalut</h4><p>Tuetut Thinking-tasot ovat <strong><code>low</code>, <code>medium</code> ja <code>high</code></strong>. Googlen kuvaamassa perusmallin tilassa oletustaso on <code>medium</code>. Nämä arvot kuvaavat Googlen perusmallia; tila ja sen ohjausmahdollisuudet Ailoot API:n kautta riippuvat valitusta menetelmästä ja malliversiosta. Tasoa <code>minimal</code> ei tueta, ja se aiheuttaa virheen. Säädettävä panos auttaa valitsemaan tilan työvaiheen vaativuuden mukaan, mutta suurella panoksella malli käyttää toisinaan enemmän tokeneita tehtävän suorittamiseen.</p><p>Ominaisuuksiin kuuluvat funktiokutsut, koodin suoritus, rakenteiset vastaukset ja kontekstin välimuisti. Tarjolla on tiedostohaku, hakutuloksiin perustuva ankkurointi, Google Maps -palvelu ja verkko-osoitteiden sisällön lukeminen. Eräkäsittelyä tuetaan. Tietokoneen käyttöliittymän ohjaus on alustava ominaisuus; se ei tee kaikista mallin kutsutavoista täysimittaista tietokoneen ohjausta.</p><h4>Käyttötarkoitus ja rajoitukset</h4><p>Valmistaja painottaa ohjelmistotekniikkaa, agenttitehtäviä ja vaativia tiedonkäsittelyprosesseja. Pitkä konteksti mahdollistaa laajojen aineistojen lähettämisen ja työkaluominaisuudet useiden toisiinsa liittyvien vaiheiden järjestämisen. Nämä ominaisuudet kuvaavat mallin kykyjä; käytettävissä olevat vaihtoehdot ja syötteet riippuvat tuetusta kutsumenetelmästä.</p><p>Versio julkaistiin vakaana syyskuussa 2026. Ilmoitettu tietojen aikaraja on maaliskuu 2026, mutta joillakin alueilla tiedot voivat olla tammikuun 2025 tasolla. Keksityt faktat, viiveet ja aikakatkaisut ovat mahdollisia. Laajempi päättely ei poista virheitä, eikä matala päättelypanos ole lupaus tietystä vastausajasta.</p>",
  "aboutText": "Gemini 3.8 Flash on tarkoitettu pitkäkestoisiin ohjelmistotekniikan tehtäviin, agenttiprosesseihin ja vaativaan tietotyöhön. Google kuvaa sitä Gemini 3.7 Flash -mallin jatkokehitykseksi, jossa painotetaan prosesseja, joiden ratkaisu ei pääty yhteen vastaukseen: malli palaa aineistoihin, käyttää työkaluja ja jatkaa vaiheketjua.\n\n### Analysoitavat aineistot\n\nGoogle ilmoittaa syötteiksi **tekstin, kuvat, videon, äänen ja PDF-tiedostot**. Ailoot API:n nykyisessä luettelossa tekstimenetelmien syötteeksi ilmoitetaan **teksti ja kuvat** ja tulosteeksi teksti. Video, ääni ja PDF eivät kuulu tähän syötevalikoimaan. Syötteen raja on **1 048 576 tokenia** ja tulosteen **65 536 tokenia**. Malli muodostaa tekstituloksen, joka voi sisältää ohjelmakoodia ja rakenteista tietoa. Kuvien ja äänen luominen ei kuulu tämän nimenomaisen version ominaisuuksiin.\n\n### Päättely ja työkalut\n\nTuetut Thinking-tasot ovat **`low`, `medium` ja `high`**. Googlen kuvaamassa perusmallin tilassa oletustaso on `medium`. Nämä arvot kuvaavat Googlen perusmallia; tila ja sen ohjausmahdollisuudet Ailoot API:n kautta riippuvat valitusta menetelmästä ja malliversiosta. Tasoa `minimal` ei tueta, ja se aiheuttaa virheen. Säädettävä panos auttaa valitsemaan tilan työvaiheen vaativuuden mukaan, mutta suurella panoksella malli käyttää toisinaan enemmän tokeneita tehtävän suorittamiseen.\n\nOminaisuuksiin kuuluvat funktiokutsut, koodin suoritus, rakenteiset vastaukset ja kontekstin välimuisti. Tarjolla on tiedostohaku, hakutuloksiin perustuva ankkurointi, Google Maps -palvelu ja verkko-osoitteiden sisällön lukeminen. Eräkäsittelyä tuetaan. Tietokoneen käyttöliittymän ohjaus on alustava ominaisuus; se ei tee kaikista mallin kutsutavoista täysimittaista tietokoneen ohjausta.\n\n### Käyttötarkoitus ja rajoitukset\n\nValmistaja painottaa ohjelmistotekniikkaa, agenttitehtäviä ja vaativia tiedonkäsittelyprosesseja. Pitkä konteksti mahdollistaa laajojen aineistojen lähettämisen ja työkaluominaisuudet useiden toisiinsa liittyvien vaiheiden järjestämisen. Nämä ominaisuudet kuvaavat mallin kykyjä; käytettävissä olevat vaihtoehdot ja syötteet riippuvat tuetusta kutsumenetelmästä.\n\nVersio julkaistiin vakaana syyskuussa 2026. Ilmoitettu tietojen aikaraja on maaliskuu 2026, mutta joillakin alueilla tiedot voivat olla tammikuun 2025 tasolla. Keksityt faktat, viiveet ja aikakatkaisut ovat mahdollisia. Laajempi päättely ei poista virheitä, eikä matala päättelypanos ole lupaus tietystä vastausajasta.",
  "editorialOverlay": {
    "copy_fields": {
      "practical_html": "<h3>Käytännön tehtävä</h3><p>Tekninen esimerkki englanniksi</p><pre><code>Continue from a failed regression check\n\nA previous patch replaced parseInt(value) with Number(value) in a quantity validator. Actual check results: &#x27;2.5&#x27; now accepted; &#x27;abc&#x27; rejected; empty string incorrectly accepted as zero. Requirement: positive whole numbers only. Propose the next focused correction and tests for those three inputs plus &#x27;3&#x27;. State which evidence supports the change.</code></pre><h4>Odotettu tulos</h4><pre><code>A revised validator, a four-case test table and an explanation tied to the supplied check results.</code></pre><h4>Tarkista tulos</h4><pre><code>Check that empty, fractional and nonnumeric values are rejected while 3 is accepted.</code></pre>"
    },
    "copy_sha256": "5475f8eae748b45932eef71b8da26c20b8445f45d2040115b694a1703e1c0430",
    "copy_source": {
      "locale": "fi",
      "pack_sha256": "0f56d90ba41881e1134accf82e57338f246f8753ca4c0cee929aaffada5d10e7",
      "record_model_id": "gemini-3.8-flash-medium",
      "source_facts_sha256": "f9cff91874a9fd2c7b34d45c0a7ce320a59f1b6854a91c0cdc4d1e83ecf30702",
      "validation_sha256": "a2ac2f28056280fc0b2ea34a501bf156d5ce155406e57e708edf30bfdf6bfdc6"
    },
    "html_sha256": "078210ab8a6cbcc2c12b9028a631cef3396a513308c6b5b42d232117737cbc99",
    "module_sha256": "ee9dc1c50b1e6a8fb7fa062030fcb4646b9aaaeb08be513b723a5a92a7290f06",
    "raw_model_unchanged": true,
    "schema": "ailoot-native-model-editorial-v1"
  },
  "locale": "fi",
  "methods": [
    {
      "html": "<div class=\"sheet-head\"><span class=\"mav\" aria-hidden=\"true\">G</span><h2 id=\"sheet-title\">Gemini 3.8 Flash Medium</h2><button class=\"icon-btn\" type=\"button\" data-close-sheet aria-label=\"Sulje\">×</button></div><div class=\"idline\"><span>Google /</span><code>gemini-3.8-flash-medium</code><button type=\"button\" id=\"copy-id\">Kopioi ID</button></div><nav class=\"card-jump-nav\" aria-label=\"Mallikortin osiot\"><button type=\"button\" data-card-jump=\"overview\">Aloitus</button><button type=\"button\" data-card-jump=\"methods\">Syötteet &amp; menetelmät</button><button type=\"button\" data-card-jump=\"pricing\">Hinnoittelu</button><button type=\"button\" data-card-jump=\"examples\">Esimerkit</button><button type=\"button\" data-card-jump=\"results\">Tulokset</button><button type=\"button\" data-card-jump=\"aliases\">Aliakset</button></nav><div class=\"card-method-tabs\" role=\"tablist\" aria-label=\"API-menetelmät\"><button type=\"button\" role=\"tab\" tabindex=\"0\" aria-controls=\"card-method-content\" aria-selected=\"true\" id=\"card-method-tab-0\" data-card-method=\"Core|messages|/v1/messages|gemini-3.8-flash-medium\">Messages</button><button type=\"button\" role=\"tab\" tabindex=\"-1\" aria-controls=\"card-method-content\" aria-selected=\"false\" id=\"card-method-tab-1\" data-card-method=\"Core|gemini|/v1beta/models/{model}:generateContent|gemini-3.8-flash-medium\">Gemini</button></div><div id=\"card-method-content\" role=\"tabpanel\" aria-labelledby=\"card-method-tab-0\"><section class=\"card-section\" data-card-section=\"overview\"><h3 tabindex=\"-1\">Aloitus</h3><p class=\"mdesc-full\">Googlen multimodaalinen malli pitkäkestoiseen ohjelmistotekniikkaan, autonomisiin agentteihin ja vaativaan tietotyöhön.</p><dl class=\"card-io\" data-card-io><div><dt>Hyväksytyt syötteet</dt><dd>Teksti · Kuvat</dd></div><div><dt>Tulokset</dt><dd>Teksti</dd></div></dl><details class=\"card-about\"><summary>Tietoa mallista</summary><p class=\"note-s\" data-model-method-boundary>Tämä kuvaus kattaa mallin ominaisuudet. Ailootissa saatavilla olevat syötteet, tulosteet ja asetukset luetellaan alla valitulle menetelmälle.</p><div class=\"mabout\" id=\"m-about\"><p>Gemini 3.8 Flash on tarkoitettu pitkäkestoisiin ohjelmistotekniikan tehtäviin, agenttiprosesseihin ja vaativaan tietotyöhön. Google kuvaa sitä Gemini 3.7 Flash -mallin jatkokehitykseksi, jossa painotetaan prosesseja, joiden ratkaisu ei pääty yhteen vastaukseen: malli palaa aineistoihin, käyttää työkaluja ja jatkaa vaiheketjua.</p><h4>Analysoitavat aineistot</h4><p>Google ilmoittaa syötteiksi <strong>tekstin, kuvat, videon, äänen ja PDF-tiedostot</strong>. Ailoot API:n nykyisessä luettelossa tekstimenetelmien syötteeksi ilmoitetaan <strong>teksti ja kuvat</strong> ja tulosteeksi teksti. Video, ääni ja PDF eivät kuulu tähän syötevalikoimaan. Syötteen raja on <strong>1 048 576 tokenia</strong> ja tulosteen <strong>65 536 tokenia</strong>. Malli muodostaa tekstituloksen, joka voi sisältää ohjelmakoodia ja rakenteista tietoa. Kuvien ja äänen luominen ei kuulu tämän nimenomaisen version ominaisuuksiin.</p><h4>Päättely ja työkalut</h4><p>Tuetut Thinking-tasot ovat <strong><code>low</code>, <code>medium</code> ja <code>high</code></strong>. Googlen kuvaamassa perusmallin tilassa oletustaso on <code>medium</code>. Nämä arvot kuvaavat Googlen perusmallia; tila ja sen ohjausmahdollisuudet Ailoot API:n kautta riippuvat valitusta menetelmästä ja malliversiosta. Tasoa <code>minimal</code> ei tueta, ja se aiheuttaa virheen. Säädettävä panos auttaa valitsemaan tilan työvaiheen vaativuuden mukaan, mutta suurella panoksella malli käyttää toisinaan enemmän tokeneita tehtävän suorittamiseen.</p><p>Ominaisuuksiin kuuluvat funktiokutsut, koodin suoritus, rakenteiset vastaukset ja kontekstin välimuisti. Tarjolla on tiedostohaku, hakutuloksiin perustuva ankkurointi, Google Maps -palvelu ja verkko-osoitteiden sisällön lukeminen. Eräkäsittelyä tuetaan. Tietokoneen käyttöliittymän ohjaus on alustava ominaisuus; se ei tee kaikista mallin kutsutavoista täysimittaista tietokoneen ohjausta.</p><h4>Käyttötarkoitus ja rajoitukset</h4><p>Valmistaja painottaa ohjelmistotekniikkaa, agenttitehtäviä ja vaativia tiedonkäsittelyprosesseja. Pitkä konteksti mahdollistaa laajojen aineistojen lähettämisen ja työkaluominaisuudet useiden toisiinsa liittyvien vaiheiden järjestämisen. Nämä ominaisuudet kuvaavat mallin kykyjä; käytettävissä olevat vaihtoehdot ja syötteet riippuvat tuetusta kutsumenetelmästä.</p><p>Versio julkaistiin vakaana syyskuussa 2026. Ilmoitettu tietojen aikaraja on maaliskuu 2026, mutta joillakin alueilla tiedot voivat olla tammikuun 2025 tasolla. Keksityt faktat, viiveet ja aikakatkaisut ovat mahdollisia. Laajempi päättely ei poista virheitä, eikä matala päättelypanos ole lupaus tietystä vastausajasta.</p></div></details></section><section class=\"card-section\" data-card-section=\"methods\"><h3 tabindex=\"-1\">Saatavilla Ailootissa · syötteet &amp; menetelmät</h3><details class=\"card-method\" open><summary><b>Ailoot · Anthropic Messages</b> <code>POST /v1/messages</code></summary><dl class=\"method-capabilities\"><div><dt>Syötetyypit</dt><dd><code>text</code>, <code>image</code></dd></div><div><dt>Tulostyypit</dt><dd><code>text</code></dd></div><div><dt>Konteksti</dt><dd>1 048 576 tokens</dd></div><div><dt>Enimmäistuloste</dt><dd>65 536 tokens</dd></div><div><dt>Tulosteen muoto</dt><dd>json tai SSE</dd></div></dl><div class=\"tw\" data-card-parameters data-typed-parameters><table><thead><tr><th>Kenttä</th><th>Tyyppi</th><th>Vaatimus</th><th>Arvot &amp; rajat</th><th>Oletus</th></tr></thead><tbody><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">model</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>gemini-3.8-flash-medium</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">messages</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>message[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>Kohteiden vähimmäismäärä: 1</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">messages[].role</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>user, assistant</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">messages[].content</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string|content_block[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">system</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string|content_block[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">max_tokens</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>integer</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>Vähimmäismäärä: 1</div><div>Rajoitus koskee: valitun mallin/kortin täsmällinen yläraja</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">stream</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>boolean</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"known\"><span class=\"card-cell-label\">Oletus</span>false</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">temperature</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>number</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">top_p</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>number</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">stop_sequences</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tools</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>tool[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tools[].name</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>Sovelletaan, kun: työkalu annettu</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tools[].description</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tools[].input_schema</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>JSON_schema</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tool_choice</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>object</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">thinking.type</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">thinking.budget_tokens</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>integer</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">output_config.effort</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">metadata</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>object</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">cache_control</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>object</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr></tbody></table></div><details class=\"card-about\" data-material-combinations><summary>Syöteaineistojen yhdistelmät</summary><p class=\"note-s\"><b>Teksti</b> · UTF8-teksti</p><p class=\"note-s\"><code>messages[].content tai type=text-lohko</code></p><p class=\"note-s\"><b>Teksti + kuva</b></p><p class=\"note-s\"><code>{type:image,source:{type:base64,media_type,data}} tai lähde, jossa type=url</code></p></details><details class=\"note-s\" data-method-contract><summary>Menetelmän parametrit ja elinkaari</summary><div class=\"tw\" data-card-table=\"contract\"><table><thead><tr><th>Parametri</th><th>Sopimus</th></tr></thead><tbody><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>material_types</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>text, image</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>required</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>model, messages, max_tokens</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>optional_controls</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>null</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>content_type</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>application/json</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>text_file_material</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen</td></tr></tbody></table></div><p>Elinkaari: <code>exact retained published method</code></p><p class=\"note-s\">Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä.</p></details></details></section><section class=\"card-section\" data-card-section=\"pricing\"><h3 tabindex=\"-1\">Hinnoittelu</h3><h4>Ailoot-menetelmien hinnat</h4><section class=\"meth\" data-route=\"Core\"><header><b><span class=\"alias\">Ailoot</span> Anthropic Messages</b><code>POST /v1/messages</code></header><dl><div><dt>Syöte</dt><dd>0,00075 $ <em>/ 1K</em></dd></div><div><dt>Tuloste</dt><dd>0,00375 $ <em>/ 1K</em></dd></div><div><dt>Välimuistin luku</dt><dd>0,000075 $ <em>/ 1K</em></dd></div></dl></section><p class=\"note-s\">Ailoot varaa arvioidun summan ennen pyyntöä. Tuloksen jälkeen lopullinen veloitus toteutetaan mitatun käytön perusteella. Suoratoiston veloituksessa käytetään lopullista käyttötietuetta. <a href=\"/docs/fi/billing/reserve/\">Varauksen ja lopullisen veloituksen toiminta →</a></p></section><section class=\"card-section\" data-card-section=\"examples\"><h3 tabindex=\"-1\">Esimerkkipyynnöt</h3><h4>Ailoot · Anthropic Messages</h4><div class=\"code-group\"><div class=\"cg-bar\"><div class=\"cg-tabs\" role=\"tablist\" aria-label=\"Koodivaihtoehdot\"><button class=\"cg-tab\" id=\"model-code-347-tab-0\" role=\"tab\" type=\"button\" aria-controls=\"model-code-347-panel-0\" aria-selected=\"true\" tabindex=\"0\">Tekstiesimerkki</button><button class=\"cg-tab\" id=\"model-code-347-tab-1\" role=\"tab\" type=\"button\" aria-controls=\"model-code-347-panel-1\" aria-selected=\"false\" tabindex=\"-1\">Syöte, kuva</button><button class=\"cg-tab\" id=\"model-code-347-tab-2\" role=\"tab\" type=\"button\" aria-controls=\"model-code-347-panel-2\" aria-selected=\"false\" tabindex=\"-1\">Python SDK</button><button class=\"cg-tab\" id=\"model-code-347-tab-3\" role=\"tab\" type=\"button\" aria-controls=\"model-code-347-panel-3\" aria-selected=\"false\" tabindex=\"-1\">Node.js SDK</button><button class=\"cg-tab\" id=\"model-code-347-tab-4\" role=\"tab\" type=\"button\" aria-controls=\"model-code-347-panel-4\" aria-selected=\"false\" tabindex=\"-1\">Python-suoratoisto</button></div><div class=\"cg-tools\"><button class=\"cg-btn cg-copy\" type=\"button\" aria-label=\"Kopioi koodi\"><svg class=\"cp\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><rect x=\"5.25\" y=\"5.25\" width=\"8.5\" height=\"8.5\" rx=\"1.75\"/><path d=\"M10.75 5.25V3.5a1.25 1.25 0 0 0-1.25-1.25H3.5A1.25 1.25 0 0 0 2.25 3.5v6a1.25 1.25 0 0 0 1.25 1.25h1.75\"/></svg><svg class=\"ok\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><path d=\"m3 8.5 3.25 3.25L13 5\"/></svg></button></div></div><div class=\"cg-body\"><div class=\"cg-pane\" id=\"model-code-347-panel-0\" role=\"tabpanel\" aria-labelledby=\"model-code-347-tab-0\"><pre data-lang=\"bash\"><code>set -eu\n: &quot;${AILOOT_API_KEY:?Set your Ailoot API key}&quot;\n: &quot;${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}&quot;\nexport AILOOT_TEXT_FILE\npython3 - &lt;&lt;&#39;PY_REQUEST&#39;\nimport json,os\nfrom pathlib import Path\np=json.loads(&#39;{&quot;model&quot;: &quot;gemini-3.8-flash-medium&quot;, &quot;max_tokens&quot;: 1024, &quot;messages&quot;: []}&#39;)\nf=Path(os.environ[&quot;AILOOT_TEXT_FILE&quot;])\nif not f.is_file():raise SystemExit(&quot;Choose your actual UTF-8 source material&quot;)\ntext=f.read_text(encoding=&quot;utf-8&quot;)\nif not text.strip():raise SystemExit(&quot;Source material must contain text&quot;)\np[&quot;messages&quot;]=[{&quot;role&quot;:&quot;user&quot;,&quot;content&quot;:&quot;Summarize this material and quote supporting source passages.\\n\\n&quot;+text}]\nPath(&quot;request.json&quot;).write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H &quot;x-api-key: $AILOOT_API_KEY&quot; -H &#39;anthropic-version: 2023-06-01&#39; -H &#39;Content-Type: application/json&#39; \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - &lt;&lt;&#39;PY_RESULT&#39;\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(&quot;result.json&quot;).read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-347-panel-1\" role=\"tabpanel\" aria-labelledby=\"model-code-347-tab-1\" hidden><pre data-lang=\"bash\"><code>set -eu\n: &quot;${AILOOT_API_KEY:?Set your Ailoot API key}&quot;\n: &quot;${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}&quot;\nexport AILOOT_IMAGE_FILE\npython3 - &lt;&lt;&#39;PY_REQUEST&#39;\nimport json,os\nfrom pathlib import Path\np=json.loads(&#39;{&quot;model&quot;: &quot;gemini-3.8-flash-medium&quot;, &quot;max_tokens&quot;: 1024, &quot;messages&quot;: [{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: [{&quot;type&quot;: &quot;text&quot;, &quot;text&quot;: &quot;Read labels and numbers in this image; flag unreadable text.&quot;}]}]}&#39;)\nimport base64\nf=Path(os.environ[&quot;AILOOT_IMAGE_FILE&quot;])\nif not f.is_file():raise SystemExit(&quot;Choose an actual PNG JPEG or WebP image&quot;)\nraw=f.read_bytes()\nmime=&quot;image/png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;image/jpeg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;image/webp&quot; if raw[:4]==b&quot;RIFF&quot; and raw[8:12]==b&quot;WEBP&quot; else None\nif not mime:raise SystemExit(&quot;Use PNG JPEG or WebP&quot;)\nb64=base64.b64encode(raw).decode()\np[&quot;messages&quot;][0][&quot;content&quot;].append({&quot;type&quot;:&quot;image&quot;,&quot;source&quot;:{&quot;type&quot;:&quot;base64&quot;,&quot;media_type&quot;:mime,&quot;data&quot;:b64}})\nPath(&quot;request.json&quot;).write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H &quot;x-api-key: $AILOOT_API_KEY&quot; -H &#39;anthropic-version: 2023-06-01&#39; -H &#39;Content-Type: application/json&#39; \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - &lt;&lt;&#39;PY_RESULT&#39;\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(&quot;result.json&quot;).read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-347-panel-2\" role=\"tabpanel\" aria-labelledby=\"model-code-347-tab-2\" hidden><pre data-lang=\"python\"><code>import anthropic\nimport os\n\nif not os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;).strip(): raise SystemExit(&quot;Set AILOOT_API_KEY before making a request&quot;)\nclient = anthropic.Anthropic(base_url=&quot;https://api.ailoot.ai&quot;, api_key=os.environ[&quot;AILOOT_API_KEY&quot;], max_retries=0)\nmsg = client.messages.create(\n    model=&quot;gemini-3.8-flash-medium&quot;,\n    max_tokens=1024,\n    messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;Explain the difference between an observation and a hypothesis in three sentences.&quot;}],\n)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\nsave_result(msg.to_dict(mode=&quot;json&quot;))\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-347-panel-3\" role=\"tabpanel\" aria-labelledby=\"model-code-347-tab-3\" hidden><pre data-lang=\"js\"><code>import Anthropic from &quot;@anthropic-ai/sdk&quot;;\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(&quot;Set AILOOT_API_KEY before making a request&quot;);\nconst client = new Anthropic({ baseURL: &quot;https://api.ailoot.ai&quot;, apiKey: process.env.AILOOT_API_KEY, maxRetries: 0 });\nconst msg = await client.messages.create({\n  model: &quot;gemini-3.8-flash-medium&quot;,\n  max_tokens: 1024,\n  messages: [{ role: &quot;user&quot;, content: &quot;Explain the difference between an observation and a hypothesis in three sentences.&quot; }],\n});\nimport { writeFileSync } from &quot;node:fs&quot;;\n\nfunction saveResult(data, stem = &quot;result&quot;) {\n  writeFileSync(stem + &quot;.json&quot;, JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) =&gt; {\n    const raw = Buffer.from(encoded, &quot;base64&quot;);\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? &quot;png&quot; : raw[0]===255 &amp;&amp; raw[1]===216 ? &quot;jpg&quot; : raw.subarray(0,4).toString()===&quot;RIFF&quot; &amp;&amp; raw.subarray(8,12).toString()===&quot;WEBP&quot; ? &quot;webp&quot; : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(&quot;Saved&quot;, file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(&quot;Content&quot;, i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(&quot;Choice&quot;, choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(&quot;Output&quot;, i, JSON.stringify(item));\n    if (item.type === &quot;image_generation_call&quot; &amp;&amp; item.result) saveBlob(item.result, item.output_format || &quot;bin&quot;, `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(&quot;Candidate/part&quot;, ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;})[mime] || &quot;bin&quot;;\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(msg);\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-347-panel-4\" role=\"tabpanel\" aria-labelledby=\"model-code-347-tab-4\" hidden><pre data-lang=\"python\"><code>import anthropic,os\nfrom pathlib import Path\n\nif not os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;).strip(): raise SystemExit(&quot;Set AILOOT_API_KEY before making a request&quot;)\nclient=anthropic.Anthropic(base_url=&quot;https://api.ailoot.ai&quot;,api_key=os.environ[&quot;AILOOT_API_KEY&quot;],max_retries=0)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\nwith client.messages.stream(model=&#39;gemini-3.8-flash-medium&#39;,max_tokens=1024,messages=[{&quot;role&quot;:&quot;user&quot;,&quot;content&quot;:&quot;Explain observations and hypotheses in three sentences.&quot;}]) as stream:\n    with Path(&quot;stream-events.jsonl&quot;).open(&quot;w&quot;,encoding=&quot;utf-8&quot;) as log:\n        for event in stream:\n            payload=event.to_dict(mode=&quot;json&quot;)\n            log.write(json.dumps(payload,ensure_ascii=False)+&quot;\\n&quot;); log.flush()\n            print(json.dumps(payload,ensure_ascii=False))\n    final=stream.get_final_message()\n    save_result(final.to_dict(mode=&quot;json&quot;),&quot;stream-result&quot;)\n</code></pre></div></div></div></section><section class=\"card-section\" data-card-section=\"results\"><h3 tabindex=\"-1\">Vastaanota ja tallenna tulokset</h3><h4>Ailoot · Anthropic Messages</h4><p class=\"note-s\">json tai SSE</p><div class=\"card-result-process\" data-all-results><h5>Säilytä kaikki valmistuneet tulokset</h5><p class=\"note-s\">Säilytä jokainen kokonainen palautettu vastaus, tiedosto ja sisällön osa.</p><p class=\"note-s\">Säilytä kaikki sisältölohkot, päättelyallekirjoitukset ja todelliset työkalukäytön ID:t. Kokoa kaikki SSE-lohkomuutokset; ensimmäinen tekstilohko ei ole koko tulos.</p></div><div class=\"card-result-process\" data-unknown-recovery><h5>Jos alkuperäinen vastaus on tarkistettava</h5><p class=\"note-s\">Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta.</p></div><details class=\"card-about\" data-output-fields><summary>Vastauksen kentät</summary><div class=\"tw\" data-card-table=\"output\"><table><thead><tr><th>Kenttä</th><th>Tyyppi</th></tr></thead><tbody><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">id</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">model</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">content[]</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>text|thinking|tool_use|other content block</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">stop_reason</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string|null</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">usage</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>object</td></tr></tbody></table></div></details><details class=\"card-about\" data-method-errors><summary>Virheet ja seuraavat vaiheet</summary><div class=\"tw\" data-card-table=\"errors\"><table><thead><tr><th>Vastaus</th><th>Ehto</th><th>Seuraava vaihe</th></tr></thead><tbody><tr><th data-cell-label=\"Vastaus\" scope=\"row\"><span class=\"card-cell-label\">Vastaus</span>400 · <code>invalid_request_error</code></th><td data-cell-label=\"Ehto\"><span class=\"card-cell-label\">Ehto</span>Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo</td><td data-cell-label=\"Seuraava vaihe\"><span class=\"card-cell-label\">Seuraava vaihe</span>Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.</td></tr></tbody></table></div></details></section><section class=\"card-section\" data-card-section=\"aliases\"><h3 tabindex=\"-1\">Aliakset</h3><h4>Mallin aliakset</h4><p class=\"note-s\"><span data-model-alias-route=\"Core\"><b>Ailoot</b> <a href=\"#m=gemini-3.8-flash-medium&amp;route=Core&amp;caller=gemini-3.8-flash-medium&amp;fmt=messages\"><code>gemini-3.8-flash-medium</code></a></span></p><h4>Menetelmäpolkujen aliakset</h4><p class=\"note-s\">Käytä yllä näytettyjä menetelmäpolkuja.</p><h4>Liittyvät kutsujan ID:t</h4><p class=\"note-s\"><a href=\"#m=gemini-3.8-flash-medium&amp;route=Core&amp;caller=gemini-3.8-flash-medium&amp;fmt=messages\"><code>gemini-3.8-flash-medium</code></a></p></section></div>",
      "method_identity": {
        "effective_request_model_id": "gemini-3.8-flash-medium",
        "fmt": "messages",
        "http": "POST",
        "path": "/v1/messages",
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core"
      },
      "method_key": "Core|messages|/v1/messages|gemini-3.8-flash-medium",
      "ordinal": 0,
      "rawMethod": {
        "cache_read": 0.075,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Keep all content blocks, thinking signatures and actual tool-use IDs. Assemble all SSE block deltas; a first text block is not the complete output.",
            "authentication": {
              "api_key_source": "AILOOT_API_KEY",
              "headers": [
                "x-api-key",
                "anthropic-version"
              ],
              "version_example": "2023-06-01"
            },
            "errors": [
              {
                "code": null,
                "condition": "Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo",
                "http_status": 400,
                "recovery": "Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Model context is not an output cap.",
              "A model-dependent field needs the exact published model profile; unspecified defaults/enums are not guessed.",
              "Tool calls propose actions; the client application returns actual observations with the returned call ID."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "create": {
                "http": "POST",
                "path": "/v1/messages"
              },
              "job_read": null,
              "mode": "synchronous_or_streamed",
              "unknown": "Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta."
            },
            "material_combinations": [
              {
                "mode": "text",
                "representation": "messages[].content tai type=text-lohko",
                "required_material": "UTF8-teksti"
              },
              {
                "availability": "Exact model input declaration and selected Source bridge required",
                "file_id_workflow": "No Ailoot upload/file-ID endpoint is introduced by this feed.",
                "mode": "text_plus_image",
                "representation": "{type:image,source:{type:base64,media_type,data}} tai lähde, jossa type=url"
              }
            ],
            "operation_modes": [
              "conversation",
              "function_tool_continuation",
              "streaming"
            ],
            "outputs": {
              "all_results": "Säilytä kaikki sisältölohkot, päättelyallekirjoitukset ja todelliset työkalukäytön ID:t. Kokoa kaikki SSE-lohkomuutokset; ensimmäinen tekstilohko ei ole koko tulos.",
              "family": "text",
              "fields": [
                {
                  "description": null,
                  "name": "id",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "model",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "content[]",
                  "type": "text|thinking|tool_use|other content block"
                },
                {
                  "description": null,
                  "name": "stop_reason",
                  "type": "string|null"
                },
                {
                  "description": null,
                  "name": "usage",
                  "type": "object"
                }
              ],
              "format": "json tai SSE"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "gemini-3.8-flash-medium"
                ],
                "enum_known": true,
                "name": "model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "min_items": 1,
                "name": "messages",
                "required": true,
                "type": "message[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "user",
                  "assistant"
                ],
                "enum_known": true,
                "name": "messages[].role",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "messages[].content",
                "required": true,
                "type": "string|content_block[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "system",
                "required": false,
                "type": "string|content_block[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "limit_scope": "valitun mallin/kortin täsmällinen yläraja",
                "minimum": 1,
                "name": "max_tokens",
                "required": true,
                "type": "integer"
              },
              {
                "availability": "source_interface",
                "default": false,
                "default_known": true,
                "enum": null,
                "enum_known": false,
                "name": "stream",
                "required": false,
                "type": "boolean"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "temperature",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "top_p",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "stop_sequences",
                "required": false,
                "type": "string[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools",
                "required": false,
                "type": "tool[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].name",
                "required": false,
                "type": "string",
                "when": "työkalu annettu"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].description",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].input_schema",
                "required": false,
                "type": "JSON_schema"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tool_choice",
                "required": false,
                "type": "object"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "thinking.type",
                "required": false,
                "type": "string"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "thinking.budget_tokens",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "output_config.effort",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "metadata",
                "required": false,
                "type": "object"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "cache_control",
                "required": false,
                "type": "object"
              }
            ],
            "profile_binding": "Exact existing Ailoot model and method; interface constraints below do not assert provider qualification.",
            "unsupported": []
          },
          "hints": [
            "Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä."
          ],
          "input": {
            "content_type": "application/json",
            "material_types": [
              "text",
              "image"
            ],
            "optional_controls": null,
            "required": [
              "model",
              "messages",
              "max_tokens"
            ],
            "text_file_material": "varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen"
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "POST",
            "path": "/v1/messages"
          },
          "operation_modes": [
            "messages"
          ],
          "output": {
            "family": [
              "text"
            ],
            "format": "JSON or supported SSE",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": 1048576,
        "examples": [
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}\"\nexport AILOOT_TEXT_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"model\": \"gemini-3.8-flash-medium\", \"max_tokens\": 1024, \"messages\": []}')\nf=Path(os.environ[\"AILOOT_TEXT_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose your actual UTF-8 source material\")\ntext=f.read_text(encoding=\"utf-8\")\nif not text.strip():raise SystemExit(\"Source material must contain text\")\np[\"messages\"]=[{\"role\":\"user\",\"content\":\"Summarize this material and quote supporting source passages.\\n\\n\"+text}]\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H \"x-api-key: $AILOOT_API_KEY\" -H 'anthropic-version: 2023-06-01' -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(\"result.json\").read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n",
            "label": "Use actual text material",
            "language": "bash"
          },
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}\"\nexport AILOOT_IMAGE_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"model\": \"gemini-3.8-flash-medium\", \"max_tokens\": 1024, \"messages\": [{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Read labels and numbers in this image; flag unreadable text.\"}]}]}')\nimport base64\nf=Path(os.environ[\"AILOOT_IMAGE_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose an actual PNG JPEG or WebP image\")\nraw=f.read_bytes()\nmime=\"image/png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"image/jpeg\" if raw.startswith(b\"\\xff\\xd8\") else \"image/webp\" if raw[:4]==b\"RIFF\" and raw[8:12]==b\"WEBP\" else None\nif not mime:raise SystemExit(\"Use PNG JPEG or WebP\")\nb64=base64.b64encode(raw).decode()\np[\"messages\"][0][\"content\"].append({\"type\":\"image\",\"source\":{\"type\":\"base64\",\"media_type\":mime,\"data\":b64}})\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H \"x-api-key: $AILOOT_API_KEY\" -H 'anthropic-version: 2023-06-01' -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(\"result.json\").read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n",
            "label": "Use your actual image",
            "language": "bash"
          },
          {
            "code": "import anthropic\nimport os\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient = anthropic.Anthropic(base_url=\"https://api.ailoot.ai\", api_key=os.environ[\"AILOOT_API_KEY\"], max_retries=0)\nmsg = client.messages.create(\n    model=\"gemini-3.8-flash-medium\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Explain the difference between an observation and a hypothesis in three sentences.\"}],\n)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(msg.to_dict(mode=\"json\"))\n",
            "label": "Python · retained SDK call",
            "language": "python"
          },
          {
            "SDK_retry_proof": {
              "field": "maxRetries",
              "scope": "normalclient options; no provider/account/proxy switches",
              "source_urls": [
                "https://raw.githubusercontent.com/openai/openai-node/master/src/client.ts",
                "https://raw.githubusercontent.com/anthropics/anthropic-sdk-typescript/main/src/client.ts"
              ],
              "value": 0
            },
            "code": "import Anthropic from \"@anthropic-ai/sdk\";\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(\"Set AILOOT_API_KEY before making a request\");\nconst client = new Anthropic({ baseURL: \"https://api.ailoot.ai\", apiKey: process.env.AILOOT_API_KEY, maxRetries: 0 });\nconst msg = await client.messages.create({\n  model: \"gemini-3.8-flash-medium\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"Explain the difference between an observation and a hypothesis in three sentences.\" }],\n});\nimport { writeFileSync } from \"node:fs\";\n\nfunction saveResult(data, stem = \"result\") {\n  writeFileSync(stem + \".json\", JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) => {\n    const raw = Buffer.from(encoded, \"base64\");\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? \"png\" : raw[0]===255 && raw[1]===216 ? \"jpg\" : raw.subarray(0,4).toString()===\"RIFF\" && raw.subarray(8,12).toString()===\"WEBP\" ? \"webp\" : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(\"Saved\", file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(\"Content\", i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(\"Choice\", choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(\"Output\", i, JSON.stringify(item));\n    if (item.type === \"image_generation_call\" && item.result) saveBlob(item.result, item.output_format || \"bin\", `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(\"Candidate/part\", ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"})[mime] || \"bin\";\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(msg);\n",
            "label": "Node.js · retained SDK call",
            "language": "js"
          },
          {
            "code": "import anthropic,os\nfrom pathlib import Path\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient=anthropic.Anthropic(base_url=\"https://api.ailoot.ai\",api_key=os.environ[\"AILOOT_API_KEY\"],max_retries=0)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nwith client.messages.stream(model='gemini-3.8-flash-medium',max_tokens=1024,messages=[{\"role\":\"user\",\"content\":\"Explain observations and hypotheses in three sentences.\"}]) as stream:\n    with Path(\"stream-events.jsonl\").open(\"w\",encoding=\"utf-8\") as log:\n        for event in stream:\n            payload=event.to_dict(mode=\"json\")\n            log.write(json.dumps(payload,ensure_ascii=False)+\"\\n\"); log.flush()\n            print(json.dumps(payload,ensure_ascii=False))\n    final=stream.get_final_message()\n    save_result(final.to_dict(mode=\"json\"),\"stream-result\")\n",
            "label": "Python streaming · complete final message",
            "language": "python"
          }
        ],
        "family": "anthropic",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "messages",
        "http": "POST",
        "img_in": null,
        "img_out": null,
        "in": 0.75,
        "input": [
          "text",
          "image"
        ],
        "label": "Anthropic Messages",
        "max_out": 65536,
        "max_tool_calls": null,
        "out": 3.75,
        "output": [
          "text"
        ],
        "path": "/v1/messages",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 3.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.075,
                "amount_unit": "usd_per_million_tokens",
                "key": "cache_read",
                "label": "Cache read",
                "side": "in"
              }
            ]
          }
        ],
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "token",
        "units": []
      }
    },
    {
      "html": "<div class=\"sheet-head\"><span class=\"mav\" aria-hidden=\"true\">G</span><h2 id=\"sheet-title\">Gemini 3.8 Flash Medium</h2><button class=\"icon-btn\" type=\"button\" data-close-sheet aria-label=\"Sulje\">×</button></div><div class=\"idline\"><span>Google /</span><code>gemini-3.8-flash-medium</code><button type=\"button\" id=\"copy-id\">Kopioi ID</button></div><nav class=\"card-jump-nav\" aria-label=\"Mallikortin osiot\"><button type=\"button\" data-card-jump=\"overview\">Aloitus</button><button type=\"button\" data-card-jump=\"methods\">Syötteet &amp; menetelmät</button><button type=\"button\" data-card-jump=\"pricing\">Hinnoittelu</button><button type=\"button\" data-card-jump=\"examples\">Esimerkit</button><button type=\"button\" data-card-jump=\"results\">Tulokset</button><button type=\"button\" data-card-jump=\"aliases\">Aliakset</button></nav><div class=\"card-method-tabs\" role=\"tablist\" aria-label=\"API-menetelmät\"><button type=\"button\" role=\"tab\" tabindex=\"-1\" aria-controls=\"card-method-content\" aria-selected=\"false\" id=\"card-method-tab-0\" data-card-method=\"Core|messages|/v1/messages|gemini-3.8-flash-medium\">Messages</button><button type=\"button\" role=\"tab\" tabindex=\"0\" aria-controls=\"card-method-content\" aria-selected=\"true\" id=\"card-method-tab-1\" data-card-method=\"Core|gemini|/v1beta/models/{model}:generateContent|gemini-3.8-flash-medium\">Gemini</button></div><div id=\"card-method-content\" role=\"tabpanel\" aria-labelledby=\"card-method-tab-1\"><section class=\"card-section\" data-card-section=\"overview\"><h3 tabindex=\"-1\">Aloitus</h3><p class=\"mdesc-full\">Googlen multimodaalinen malli pitkäkestoiseen ohjelmistotekniikkaan, autonomisiin agentteihin ja vaativaan tietotyöhön.</p><dl class=\"card-io\" data-card-io><div><dt>Hyväksytyt syötteet</dt><dd>Teksti · Kuvat</dd></div><div><dt>Tulokset</dt><dd>Teksti</dd></div></dl><details class=\"card-about\"><summary>Tietoa mallista</summary><p class=\"note-s\" data-model-method-boundary>Tämä kuvaus kattaa mallin ominaisuudet. Ailootissa saatavilla olevat syötteet, tulosteet ja asetukset luetellaan alla valitulle menetelmälle.</p><div class=\"mabout\" id=\"m-about\"><p>Gemini 3.8 Flash on tarkoitettu pitkäkestoisiin ohjelmistotekniikan tehtäviin, agenttiprosesseihin ja vaativaan tietotyöhön. Google kuvaa sitä Gemini 3.7 Flash -mallin jatkokehitykseksi, jossa painotetaan prosesseja, joiden ratkaisu ei pääty yhteen vastaukseen: malli palaa aineistoihin, käyttää työkaluja ja jatkaa vaiheketjua.</p><h4>Analysoitavat aineistot</h4><p>Google ilmoittaa syötteiksi <strong>tekstin, kuvat, videon, äänen ja PDF-tiedostot</strong>. Ailoot API:n nykyisessä luettelossa tekstimenetelmien syötteeksi ilmoitetaan <strong>teksti ja kuvat</strong> ja tulosteeksi teksti. Video, ääni ja PDF eivät kuulu tähän syötevalikoimaan. Syötteen raja on <strong>1 048 576 tokenia</strong> ja tulosteen <strong>65 536 tokenia</strong>. Malli muodostaa tekstituloksen, joka voi sisältää ohjelmakoodia ja rakenteista tietoa. Kuvien ja äänen luominen ei kuulu tämän nimenomaisen version ominaisuuksiin.</p><h4>Päättely ja työkalut</h4><p>Tuetut Thinking-tasot ovat <strong><code>low</code>, <code>medium</code> ja <code>high</code></strong>. Googlen kuvaamassa perusmallin tilassa oletustaso on <code>medium</code>. Nämä arvot kuvaavat Googlen perusmallia; tila ja sen ohjausmahdollisuudet Ailoot API:n kautta riippuvat valitusta menetelmästä ja malliversiosta. Tasoa <code>minimal</code> ei tueta, ja se aiheuttaa virheen. Säädettävä panos auttaa valitsemaan tilan työvaiheen vaativuuden mukaan, mutta suurella panoksella malli käyttää toisinaan enemmän tokeneita tehtävän suorittamiseen.</p><p>Ominaisuuksiin kuuluvat funktiokutsut, koodin suoritus, rakenteiset vastaukset ja kontekstin välimuisti. Tarjolla on tiedostohaku, hakutuloksiin perustuva ankkurointi, Google Maps -palvelu ja verkko-osoitteiden sisällön lukeminen. Eräkäsittelyä tuetaan. Tietokoneen käyttöliittymän ohjaus on alustava ominaisuus; se ei tee kaikista mallin kutsutavoista täysimittaista tietokoneen ohjausta.</p><h4>Käyttötarkoitus ja rajoitukset</h4><p>Valmistaja painottaa ohjelmistotekniikkaa, agenttitehtäviä ja vaativia tiedonkäsittelyprosesseja. Pitkä konteksti mahdollistaa laajojen aineistojen lähettämisen ja työkaluominaisuudet useiden toisiinsa liittyvien vaiheiden järjestämisen. Nämä ominaisuudet kuvaavat mallin kykyjä; käytettävissä olevat vaihtoehdot ja syötteet riippuvat tuetusta kutsumenetelmästä.</p><p>Versio julkaistiin vakaana syyskuussa 2026. Ilmoitettu tietojen aikaraja on maaliskuu 2026, mutta joillakin alueilla tiedot voivat olla tammikuun 2025 tasolla. Keksityt faktat, viiveet ja aikakatkaisut ovat mahdollisia. Laajempi päättely ei poista virheitä, eikä matala päättelypanos ole lupaus tietystä vastausajasta.</p></div></details></section><section class=\"card-section\" data-card-section=\"methods\"><h3 tabindex=\"-1\">Saatavilla Ailootissa · syötteet &amp; menetelmät</h3><details class=\"card-method\" open><summary><b>Ailoot · Gemini generateContent</b> <code>POST /v1beta/models/{model}:generateContent</code></summary><dl class=\"method-capabilities\"><div><dt>Syötetyypit</dt><dd><code>text</code>, <code>image</code></dd></div><div><dt>Tulostyypit</dt><dd><code>text</code></dd></div><div><dt>Tulosteen muoto</dt><dd>json tai tuettu virtakäsittely</dd></div></dl><div class=\"tw\" data-card-parameters data-typed-parameters><table><thead><tr><th>Kenttä</th><th>Tyyppi</th><th>Vaatimus</th><th>Arvot &amp; rajat</th><th>Oletus</th></tr></thead><tbody><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">path.model</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>gemini-3.8-flash-medium</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">contents</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>content[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>Kohteiden vähimmäismäärä: 1</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">contents[].role</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>user, model</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">contents[].parts</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>part[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Pakollinen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">systemInstruction</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>content</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.maxOutputTokens</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>integer</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div>Vähimmäismäärä: 1</div><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.temperature</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>number</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.topP</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>number</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.topK</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>integer</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.stopSequences</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.thinkingConfig.includeThoughts</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>boolean</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">generationConfig.thinkingConfig.thinkingBudget</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>integer</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">tools[].functionDeclarations</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>function_declaration[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">toolConfig.functionCallingConfig.mode</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"model_dependent\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">safetySettings</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>object[]</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span><div class=\"note-s\">Riippuu mallista</div></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr><tr data-parameter-availability=\"source_interface\"><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">sessionId</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span><code>string</code></td><td data-cell-label=\"Vaatimus\"><span class=\"card-cell-label\">Vaatimus</span>Valinnainen</td><td data-cell-label=\"Arvot &amp; rajat\"><span class=\"card-cell-label\">Arvot &amp; rajat</span></td><td data-cell-label=\"Oletus\" data-default=\"unspecified\"><span class=\"card-cell-label\">Oletus</span>—</td></tr></tbody></table></div><details class=\"card-about\" data-material-combinations><summary>Syöteaineistojen yhdistelmät</summary><p class=\"note-s\"><b>Teksti</b> · UTF8-teksti</p><p class=\"note-s\"><code>contents[].parts[].text</code></p><p class=\"note-s\"><b>Teksti + kuva</b></p><p class=\"note-s\"><code>parts[].inlineData={mimeType,data}</code></p></details><details class=\"note-s\" data-method-contract><summary>Menetelmän parametrit ja elinkaari</summary><div class=\"tw\" data-card-table=\"contract\"><table><thead><tr><th>Parametri</th><th>Sopimus</th></tr></thead><tbody><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>material_types</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>text, image</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>required</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>contents</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>optional_controls</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>null</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>content_type</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>application/json</td></tr><tr><th data-cell-label=\"Parametri\" scope=\"row\"><span class=\"card-cell-label\">Parametri</span><code>text_file_material</code></th><td data-cell-label=\"Sopimus\"><span class=\"card-cell-label\">Sopimus</span>varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen</td></tr></tbody></table></div><p>Elinkaari: <code>exact retained published method</code></p><p class=\"note-s\">Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä.</p></details></details></section><section class=\"card-section\" data-card-section=\"pricing\"><h3 tabindex=\"-1\">Hinnoittelu</h3><h4>Ailoot-menetelmien hinnat</h4><section class=\"meth\" data-route=\"Core\"><header><b><span class=\"alias\">Ailoot</span> Gemini generateContent</b><code>POST /v1beta/models/{model}:generateContent</code></header><dl><div><dt>Syöte</dt><dd>0,00075 $ <em>/ 1K</em></dd></div><div><dt>Tuloste</dt><dd>0,00375 $ <em>/ 1K</em></dd></div><div><dt>Välimuistin luku</dt><dd>0,000075 $ <em>/ 1K</em></dd></div></dl></section><p class=\"note-s\">Ailoot varaa arvioidun summan ennen pyyntöä. Tuloksen jälkeen lopullinen veloitus toteutetaan mitatun käytön perusteella. Suoratoiston veloituksessa käytetään lopullista käyttötietuetta. <a href=\"/docs/fi/billing/reserve/\">Varauksen ja lopullisen veloituksen toiminta →</a></p></section><section class=\"card-section\" data-card-section=\"examples\"><h3 tabindex=\"-1\">Esimerkkipyynnöt</h3><h4>Ailoot · Gemini generateContent</h4><div class=\"code-group\"><div class=\"cg-bar\"><div class=\"cg-tabs\" role=\"tablist\" aria-label=\"Koodivaihtoehdot\"><button class=\"cg-tab\" id=\"model-code-348-tab-0\" role=\"tab\" type=\"button\" aria-controls=\"model-code-348-panel-0\" aria-selected=\"true\" tabindex=\"0\">Tekstiesimerkki</button><button class=\"cg-tab\" id=\"model-code-348-tab-1\" role=\"tab\" type=\"button\" aria-controls=\"model-code-348-panel-1\" aria-selected=\"false\" tabindex=\"-1\">Syöte, kuva</button><button class=\"cg-tab\" id=\"model-code-348-tab-2\" role=\"tab\" type=\"button\" aria-controls=\"model-code-348-panel-2\" aria-selected=\"false\" tabindex=\"-1\">Python SDK</button><button class=\"cg-tab\" id=\"model-code-348-tab-3\" role=\"tab\" type=\"button\" aria-controls=\"model-code-348-panel-3\" aria-selected=\"false\" tabindex=\"-1\">Node.js SDK</button><button class=\"cg-tab\" id=\"model-code-348-tab-4\" role=\"tab\" type=\"button\" aria-controls=\"model-code-348-panel-4\" aria-selected=\"false\" tabindex=\"-1\">Python-suoratoisto</button></div><div class=\"cg-tools\"><button class=\"cg-btn cg-copy\" type=\"button\" aria-label=\"Kopioi koodi\"><svg class=\"cp\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><rect x=\"5.25\" y=\"5.25\" width=\"8.5\" height=\"8.5\" rx=\"1.75\"/><path d=\"M10.75 5.25V3.5a1.25 1.25 0 0 0-1.25-1.25H3.5A1.25 1.25 0 0 0 2.25 3.5v6a1.25 1.25 0 0 0 1.25 1.25h1.75\"/></svg><svg class=\"ok\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><path d=\"m3 8.5 3.25 3.25L13 5\"/></svg></button></div></div><div class=\"cg-body\"><div class=\"cg-pane\" id=\"model-code-348-panel-0\" role=\"tabpanel\" aria-labelledby=\"model-code-348-tab-0\"><pre data-lang=\"bash\"><code>set -eu\n: &quot;${AILOOT_API_KEY:?Set your Ailoot API key}&quot;\n: &quot;${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}&quot;\nexport AILOOT_TEXT_FILE\npython3 - &lt;&lt;&#39;PY_REQUEST&#39;\nimport json,os\nfrom pathlib import Path\np=json.loads(&#39;{&quot;contents&quot;: []}&#39;)\nf=Path(os.environ[&quot;AILOOT_TEXT_FILE&quot;])\nif not f.is_file():raise SystemExit(&quot;Choose your actual UTF-8 source material&quot;)\ntext=f.read_text(encoding=&quot;utf-8&quot;)\nif not text.strip():raise SystemExit(&quot;Source material must contain text&quot;)\np[&quot;contents&quot;]=[{&quot;role&quot;:&quot;user&quot;,&quot;parts&quot;:[{&quot;text&quot;:&quot;Summarize this material and quote supporting source passages.\\n\\n&quot;+text}]}]\nPath(&quot;request.json&quot;).write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H &quot;x-goog-api-key: $AILOOT_API_KEY&quot; -H &#39;Content-Type: application/json&#39; \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - &lt;&lt;&#39;PY_RESULT&#39;\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\nsave_result(json.loads(Path(&quot;result.json&quot;).read_text(encoding=&quot;utf-8&quot;)))\nPY_RESULT\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-348-panel-1\" role=\"tabpanel\" aria-labelledby=\"model-code-348-tab-1\" hidden><pre data-lang=\"bash\"><code>set -eu\n: &quot;${AILOOT_API_KEY:?Set your Ailoot API key}&quot;\n: &quot;${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}&quot;\nexport AILOOT_IMAGE_FILE\npython3 - &lt;&lt;&#39;PY_REQUEST&#39;\nimport json,os\nfrom pathlib import Path\np=json.loads(&#39;{&quot;contents&quot;: [{&quot;role&quot;: &quot;user&quot;, &quot;parts&quot;: [{&quot;text&quot;: &quot;Read labels and numbers in this image; flag unreadable text.&quot;}]}]}&#39;)\nimport base64\nf=Path(os.environ[&quot;AILOOT_IMAGE_FILE&quot;])\nif not f.is_file():raise SystemExit(&quot;Choose an actual PNG JPEG or WebP image&quot;)\nraw=f.read_bytes()\nmime=&quot;image/png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;image/jpeg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;image/webp&quot; if raw[:4]==b&quot;RIFF&quot; and raw[8:12]==b&quot;WEBP&quot; else None\nif not mime:raise SystemExit(&quot;Use PNG JPEG or WebP&quot;)\nb64=base64.b64encode(raw).decode()\np[&quot;contents&quot;][0][&quot;parts&quot;].append({&quot;inlineData&quot;:{&quot;mimeType&quot;:mime,&quot;data&quot;:b64}})\nPath(&quot;request.json&quot;).write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H &quot;x-goog-api-key: $AILOOT_API_KEY&quot; -H &#39;Content-Type: application/json&#39; \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - &lt;&lt;&#39;PY_RESULT&#39;\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\nsave_result(json.loads(Path(&quot;result.json&quot;).read_text(encoding=&quot;utf-8&quot;)))\nPY_RESULT\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-348-panel-2\" role=\"tabpanel\" aria-labelledby=\"model-code-348-tab-2\" hidden><pre data-lang=\"python\"><code>from google import genai\nfrom google.genai import types\nimport os\n\nif not os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;).strip(): raise SystemExit(&quot;Set AILOOT_API_KEY before making a request&quot;)\nclient = genai.Client(\n    api_key=os.environ[&quot;AILOOT_API_KEY&quot;],\n    http_options=types.HttpOptions(base_url=&quot;https://api.ailoot.ai&quot;),\n)\nresp = client.models.generate_content(model=&quot;gemini-3.8-flash-medium&quot;, contents=&quot;Explain the difference between an observation and a hypothesis in three sentences.&quot;)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\nsave_result(resp.to_json_dict())\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-348-panel-3\" role=\"tabpanel\" aria-labelledby=\"model-code-348-tab-3\" hidden><pre data-lang=\"js\"><code>import { GoogleGenAI } from &quot;@google/genai&quot;;\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(&quot;Set AILOOT_API_KEY before making a request&quot;);\nconst ai = new GoogleGenAI({ apiKey: process.env.AILOOT_API_KEY, httpOptions: { baseUrl: &quot;https://api.ailoot.ai&quot; } });\nconst resp = await ai.models.generateContent({ model: &quot;gemini-3.8-flash-medium&quot;, contents: &quot;Explain the difference between an observation and a hypothesis in three sentences.&quot; });\nimport { writeFileSync } from &quot;node:fs&quot;;\n\nfunction saveResult(data, stem = &quot;result&quot;) {\n  writeFileSync(stem + &quot;.json&quot;, JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) =&gt; {\n    const raw = Buffer.from(encoded, &quot;base64&quot;);\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? &quot;png&quot; : raw[0]===255 &amp;&amp; raw[1]===216 ? &quot;jpg&quot; : raw.subarray(0,4).toString()===&quot;RIFF&quot; &amp;&amp; raw.subarray(8,12).toString()===&quot;WEBP&quot; ? &quot;webp&quot; : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(&quot;Saved&quot;, file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(&quot;Content&quot;, i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(&quot;Choice&quot;, choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(&quot;Output&quot;, i, JSON.stringify(item));\n    if (item.type === &quot;image_generation_call&quot; &amp;&amp; item.result) saveBlob(item.result, item.output_format || &quot;bin&quot;, `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(&quot;Candidate/part&quot;, ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;})[mime] || &quot;bin&quot;;\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(resp);\n</code></pre></div><div class=\"cg-pane\" id=\"model-code-348-panel-4\" role=\"tabpanel\" aria-labelledby=\"model-code-348-tab-4\" hidden><pre data-lang=\"python\"><code>from google import genai\nfrom google.genai import types\nimport os\nfrom pathlib import Path\n\nif not os.environ.get(&quot;AILOOT_API_KEY&quot;, &quot;&quot;).strip(): raise SystemExit(&quot;Set AILOOT_API_KEY before making a request&quot;)\nclient=genai.Client(api_key=os.environ[&quot;AILOOT_API_KEY&quot;],http_options=types.HttpOptions(base_url=&quot;https://api.ailoot.ai&quot;))\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=&quot;result&quot;):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + &quot;.json&quot;).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=&quot;utf-8&quot;)\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b&quot;-_&quot;, validate=True)\n        ext = &quot;png&quot; if raw.startswith(b&quot;\\x89PNG\\r\\n\\x1a\\n&quot;) else &quot;jpg&quot; if raw.startswith(b&quot;\\xff\\xd8&quot;) else &quot;webp&quot; if raw[:4] == b&quot;RIFF&quot; and raw[8:12] == b&quot;WEBP&quot; else suffix\n        file = Path(stem + &quot;-&quot; + label + &quot;.&quot; + ext)\n        file.write_bytes(raw)\n        print(&quot;Saved&quot;, file)\n    for index, block in enumerate(data.get(&quot;content&quot;) or []):\n        print(&quot;Content&quot;, index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(&quot;choices&quot;) or []:\n        print(&quot;Choice&quot;, choice.get(&quot;index&quot;), json.dumps(choice.get(&quot;message&quot;, choice.get(&quot;delta&quot;, {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(&quot;output&quot;) or []):\n        print(&quot;Output&quot;, index, json.dumps(item, ensure_ascii=False))\n        if item.get(&quot;type&quot;) == &quot;image_generation_call&quot; and item.get(&quot;result&quot;):\n            save_blob(item[&quot;result&quot;], item.get(&quot;output_format&quot;) or &quot;bin&quot;, &quot;output-&quot; + str(index))\n    for ci, candidate in enumerate(data.get(&quot;candidates&quot;) or []):\n        for pi, part in enumerate((candidate.get(&quot;content&quot;) or {}).get(&quot;parts&quot;) or []):\n            print(&quot;Candidate/part&quot;, ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(&quot;inlineData&quot;) or part.get(&quot;inline_data&quot;)\n            if blob and blob.get(&quot;data&quot;):\n                mime = blob.get(&quot;mimeType&quot;) or blob.get(&quot;mime_type&quot;)\n                suffix = {&quot;image/png&quot;:&quot;png&quot;, &quot;image/jpeg&quot;:&quot;jpg&quot;, &quot;image/webp&quot;:&quot;webp&quot;, &quot;audio/wav&quot;:&quot;wav&quot;, &quot;audio/mpeg&quot;:&quot;mp3&quot;, &quot;video/mp4&quot;:&quot;mp4&quot;}.get(mime, &quot;bin&quot;)\n                save_blob(blob[&quot;data&quot;], suffix, &quot;candidate-&quot; + str(ci) + &quot;-part-&quot; + str(pi))\n\ncount=0\nwith Path(&quot;stream-events.jsonl&quot;).open(&quot;w&quot;,encoding=&quot;utf-8&quot;) as log:\n    for chunk in client.models.generate_content_stream(model=&#39;gemini-3.8-flash-medium&#39;,contents=&quot;Explain observations and hypotheses in three sentences.&quot;):\n        payload=chunk.to_json_dict()\n        log.write(json.dumps(payload,ensure_ascii=False)+&quot;\\n&quot;); log.flush()\n        save_result(payload,&quot;stream-chunk-&quot;+str(count))\n        count+=1\n</code></pre></div></div></div></section><section class=\"card-section\" data-card-section=\"results\"><h3 tabindex=\"-1\">Vastaanota ja tallenna tulokset</h3><h4>Ailoot · Gemini generateContent</h4><p class=\"note-s\">json tai tuettu virtakäsittely</p><div class=\"card-result-process\" data-all-results><h5>Säilytä kaikki valmistuneet tulokset</h5><p class=\"note-s\">Säilytä jokainen kokonainen palautettu vastaus, tiedosto ja sisällön osa.</p><p class=\"note-s\">Säilytä kaikki ehdokkaat ja osat, mukaan lukien funktiokutsut, päättelyallekirjoitukset ja käyttötiedot; kokoa virran lohkot järjestyksessä.</p></div><div class=\"card-result-process\" data-unknown-recovery><h5>Jos alkuperäinen vastaus on tarkistettava</h5><p class=\"note-s\">Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta.</p></div><details class=\"card-about\" data-output-fields><summary>Vastauksen kentät</summary><div class=\"tw\" data-card-table=\"output\"><table><thead><tr><th>Kenttä</th><th>Tyyppi</th></tr></thead><tbody><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">responseId</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">modelVersion</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">candidates[].content.parts[]</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>text|inlineData|functionCall|other part</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">candidates[].finishReason</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>string</td></tr><tr><th data-cell-label=\"Kenttä\" scope=\"row\"><span class=\"card-cell-label\">Kenttä</span><code class=\"card-field-name\">usageMetadata</code></th><td data-cell-label=\"Tyyppi\" data-field-type><span class=\"card-cell-label\">Tyyppi</span>object</td></tr></tbody></table></div></details><details class=\"card-about\" data-method-errors><summary>Virheet ja seuraavat vaiheet</summary><div class=\"tw\" data-card-table=\"errors\"><table><thead><tr><th>Vastaus</th><th>Ehto</th><th>Seuraava vaihe</th></tr></thead><tbody><tr><th data-cell-label=\"Vastaus\" scope=\"row\"><span class=\"card-cell-label\">Vastaus</span>400 · <code>invalid_request_error</code></th><td data-cell-label=\"Ehto\"><span class=\"card-cell-label\">Ehto</span>Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo</td><td data-cell-label=\"Seuraava vaihe\"><span class=\"card-cell-label\">Seuraava vaihe</span>Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.</td></tr></tbody></table></div></details></section><section class=\"card-section\" data-card-section=\"aliases\"><h3 tabindex=\"-1\">Aliakset</h3><h4>Mallin aliakset</h4><p class=\"note-s\"><span data-model-alias-route=\"Core\"><b>Ailoot</b> <a href=\"#m=gemini-3.8-flash-medium&amp;route=Core&amp;caller=gemini-3.8-flash-medium&amp;fmt=gemini\"><code>gemini-3.8-flash-medium</code></a></span></p><h4>Menetelmäpolkujen aliakset</h4><p class=\"note-s\">Käytä yllä näytettyjä menetelmäpolkuja.</p><h4>Liittyvät kutsujan ID:t</h4><p class=\"note-s\"><a href=\"#m=gemini-3.8-flash-medium&amp;route=Core&amp;caller=gemini-3.8-flash-medium&amp;fmt=gemini\"><code>gemini-3.8-flash-medium</code></a></p></section></div>",
      "method_identity": {
        "effective_request_model_id": "gemini-3.8-flash-medium",
        "fmt": "gemini",
        "http": "POST",
        "path": "/v1beta/models/{model}:generateContent",
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core"
      },
      "method_key": "Core|gemini|/v1beta/models/{model}:generateContent|gemini-3.8-flash-medium",
      "ordinal": 1,
      "rawMethod": {
        "cache_read": 0.075,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Keep all candidates and parts, including function calls, thought signatures and usage; assemble stream chunks in order.",
            "authentication": {
              "api_key_source": "AILOOT_API_KEY",
              "header": "x-goog-api-key"
            },
            "errors": [
              {
                "code": null,
                "condition": "Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo",
                "http_status": 400,
                "recovery": "Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Model context is not an output cap.",
              "A model-dependent field needs the exact published model profile; unspecified defaults/enums are not guessed.",
              "Tool calls propose actions; the client application returns actual observations with the returned call ID."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "create": {
                "http": "POST",
                "path": "/v1beta/models/{model}:generateContent"
              },
              "job_read": null,
              "mode": "synchronous_or_streamed",
              "unknown": "Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta."
            },
            "material_combinations": [
              {
                "mode": "text",
                "representation": "contents[].parts[].text",
                "required_material": "UTF8-teksti"
              },
              {
                "availability": "Exact model input declaration and selected Source bridge required",
                "file_id_workflow": "No Ailoot upload/file-ID endpoint is introduced by this feed.",
                "mode": "text_plus_image",
                "representation": "parts[].inlineData={mimeType,data}"
              }
            ],
            "operation_modes": [
              "conversation",
              "function_tool_continuation",
              "generate_content"
            ],
            "outputs": {
              "all_results": "Säilytä kaikki ehdokkaat ja osat, mukaan lukien funktiokutsut, päättelyallekirjoitukset ja käyttötiedot; kokoa virran lohkot järjestyksessä.",
              "family": "text",
              "fields": [
                {
                  "description": null,
                  "name": "responseId",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "modelVersion",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "candidates[].content.parts[]",
                  "type": "text|inlineData|functionCall|other part"
                },
                {
                  "description": null,
                  "name": "candidates[].finishReason",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "usageMetadata",
                  "type": "object"
                }
              ],
              "format": "json tai tuettu virtakäsittely"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "gemini-3.8-flash-medium"
                ],
                "enum_known": true,
                "name": "path.model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "min_items": 1,
                "name": "contents",
                "required": true,
                "type": "content[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "user",
                  "model"
                ],
                "enum_known": true,
                "name": "contents[].role",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "contents[].parts",
                "required": true,
                "type": "part[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "systemInstruction",
                "required": false,
                "type": "content"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "minimum": 1,
                "name": "generationConfig.maxOutputTokens",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.temperature",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.topP",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.topK",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.stopSequences",
                "required": false,
                "type": "string[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.thinkingConfig.includeThoughts",
                "required": false,
                "type": "boolean"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.thinkingConfig.thinkingBudget",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].functionDeclarations",
                "required": false,
                "type": "function_declaration[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "toolConfig.functionCallingConfig.mode",
                "required": false,
                "type": "string"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "safetySettings",
                "required": false,
                "type": "object[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "sessionId",
                "required": false,
                "type": "string"
              }
            ],
            "profile_binding": "Exact existing Ailoot model and method; interface constraints below do not assert provider qualification.",
            "unsupported": []
          },
          "hints": [
            "Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä."
          ],
          "input": {
            "content_type": "application/json",
            "material_types": [
              "text",
              "image"
            ],
            "optional_controls": null,
            "required": [
              "contents"
            ],
            "text_file_material": "varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen"
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "POST",
            "path": "/v1beta/models/{model}:generateContent"
          },
          "operation_modes": [
            "gemini"
          ],
          "output": {
            "family": [
              "text"
            ],
            "format": "JSON or supported SSE",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": null,
        "examples": [
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}\"\nexport AILOOT_TEXT_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"contents\": []}')\nf=Path(os.environ[\"AILOOT_TEXT_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose your actual UTF-8 source material\")\ntext=f.read_text(encoding=\"utf-8\")\nif not text.strip():raise SystemExit(\"Source material must contain text\")\np[\"contents\"]=[{\"role\":\"user\",\"parts\":[{\"text\":\"Summarize this material and quote supporting source passages.\\n\\n\"+text}]}]\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H \"x-goog-api-key: $AILOOT_API_KEY\" -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(json.loads(Path(\"result.json\").read_text(encoding=\"utf-8\")))\nPY_RESULT\n",
            "label": "Use actual text material",
            "language": "bash"
          },
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}\"\nexport AILOOT_IMAGE_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"Read labels and numbers in this image; flag unreadable text.\"}]}]}')\nimport base64\nf=Path(os.environ[\"AILOOT_IMAGE_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose an actual PNG JPEG or WebP image\")\nraw=f.read_bytes()\nmime=\"image/png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"image/jpeg\" if raw.startswith(b\"\\xff\\xd8\") else \"image/webp\" if raw[:4]==b\"RIFF\" and raw[8:12]==b\"WEBP\" else None\nif not mime:raise SystemExit(\"Use PNG JPEG or WebP\")\nb64=base64.b64encode(raw).decode()\np[\"contents\"][0][\"parts\"].append({\"inlineData\":{\"mimeType\":mime,\"data\":b64}})\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H \"x-goog-api-key: $AILOOT_API_KEY\" -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(json.loads(Path(\"result.json\").read_text(encoding=\"utf-8\")))\nPY_RESULT\n",
            "label": "Use your actual image",
            "language": "bash"
          },
          {
            "code": "from google import genai\nfrom google.genai import types\nimport os\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient = genai.Client(\n    api_key=os.environ[\"AILOOT_API_KEY\"],\n    http_options=types.HttpOptions(base_url=\"https://api.ailoot.ai\"),\n)\nresp = client.models.generate_content(model=\"gemini-3.8-flash-medium\", contents=\"Explain the difference between an observation and a hypothesis in three sentences.\")\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(resp.to_json_dict())\n",
            "label": "Python · retained SDK call",
            "language": "python"
          },
          {
            "code": "import { GoogleGenAI } from \"@google/genai\";\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(\"Set AILOOT_API_KEY before making a request\");\nconst ai = new GoogleGenAI({ apiKey: process.env.AILOOT_API_KEY, httpOptions: { baseUrl: \"https://api.ailoot.ai\" } });\nconst resp = await ai.models.generateContent({ model: \"gemini-3.8-flash-medium\", contents: \"Explain the difference between an observation and a hypothesis in three sentences.\" });\nimport { writeFileSync } from \"node:fs\";\n\nfunction saveResult(data, stem = \"result\") {\n  writeFileSync(stem + \".json\", JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) => {\n    const raw = Buffer.from(encoded, \"base64\");\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? \"png\" : raw[0]===255 && raw[1]===216 ? \"jpg\" : raw.subarray(0,4).toString()===\"RIFF\" && raw.subarray(8,12).toString()===\"WEBP\" ? \"webp\" : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(\"Saved\", file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(\"Content\", i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(\"Choice\", choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(\"Output\", i, JSON.stringify(item));\n    if (item.type === \"image_generation_call\" && item.result) saveBlob(item.result, item.output_format || \"bin\", `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(\"Candidate/part\", ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"})[mime] || \"bin\";\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(resp);\n",
            "label": "Node.js · retained SDK call",
            "language": "js"
          },
          {
            "code": "from google import genai\nfrom google.genai import types\nimport os\nfrom pathlib import Path\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient=genai.Client(api_key=os.environ[\"AILOOT_API_KEY\"],http_options=types.HttpOptions(base_url=\"https://api.ailoot.ai\"))\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\ncount=0\nwith Path(\"stream-events.jsonl\").open(\"w\",encoding=\"utf-8\") as log:\n    for chunk in client.models.generate_content_stream(model='gemini-3.8-flash-medium',contents=\"Explain observations and hypotheses in three sentences.\"):\n        payload=chunk.to_json_dict()\n        log.write(json.dumps(payload,ensure_ascii=False)+\"\\n\"); log.flush()\n        save_result(payload,\"stream-chunk-\"+str(count))\n        count+=1\n",
            "label": "Python streaming · retain all chunks",
            "language": "python"
          }
        ],
        "family": "gemini",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "gemini",
        "http": "POST",
        "img_in": null,
        "img_out": null,
        "in": 0.75,
        "input": [
          "text",
          "image"
        ],
        "label": "Gemini generateContent",
        "max_out": null,
        "max_tool_calls": null,
        "out": 3.75,
        "output": [
          "text"
        ],
        "path": "/v1beta/models/{model}:generateContent",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 3.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.075,
                "amount_unit": "usd_per_million_tokens",
                "key": "cache_read",
                "label": "Cache read",
                "side": "in"
              }
            ]
          }
        ],
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "token",
        "units": []
      }
    }
  ],
  "model_id": "gemini-3.8-flash-medium",
  "nativeProvenance": {
    "input_facts_canonical_sha256": "118eedf65fea5cc63f4ffb2f5a435f1a5b3f841b7fe184f970ece92a964e6d87",
    "input_html_sha256": "12d6c336b99572821fc18ad58e1ed6f4367d7957d6c1529a55df47c6d9bf3427",
    "private_audit_sha256": "896c32627f22bcb9c1ce478087fcff65e6e5b289f77ce02670a461e8c9e1006e",
    "role": "historical-normalized-input-audit-hashes",
    "schema": "ailoot-native-model-provenance-v2"
  },
  "page": {
    "canonical": "https://ailoot.ai/models/fi/gemini-3-8-flash-medium/",
    "description": "Googlen multimodaalinen malli pitkäkestoiseen ohjelmistotekniikkaan, autonomisiin agentteihin ja vaativaan tietotyöhön.",
    "locale": "fi",
    "md_url": "https://ailoot.ai/models/fi/gemini-3-8-flash-medium/index.md",
    "title": "Gemini 3.8 Flash Medium — Ailoot",
    "url": "https://ailoot.ai/models/fi/gemini-3-8-flash-medium/"
  },
  "practicalHtml": "<h3>Käytännön tehtävä</h3><p>Tekninen esimerkki englanniksi</p><pre><code>Continue from a failed regression check\n\nA previous patch replaced parseInt(value) with Number(value) in a quantity validator. Actual check results: &#x27;2.5&#x27; now accepted; &#x27;abc&#x27; rejected; empty string incorrectly accepted as zero. Requirement: positive whole numbers only. Propose the next focused correction and tests for those three inputs plus &#x27;3&#x27;. State which evidence supports the change.</code></pre><h4>Odotettu tulos</h4><pre><code>A revised validator, a four-case test table and an explanation tied to the supplied check results.</code></pre><h4>Tarkista tulos</h4><pre><code>Check that empty, fractional and nonnumeric values are rejected while 3 is accepted.</code></pre>",
  "practicalText": "Käytännön tehtävä Tekninen esimerkki englanniksi Continue from a failed regression check A previous patch replaced parseInt(value) with Number(value) in a quantity validator. Actual check results: '2.5' now accepted; 'abc' rejected; empty string incorrectly accepted as zero. Requirement: positive whole numbers only. Propose the next focused correction and tests for those three inputs plus '3'. State which evidence supports the change. Odotettu tulos A revised validator, a four-case test table and an explanation tied to the supplied check results. Tarkista tulos Check that empty, fractional and nonnumeric values are rejected while 3 is accepted.",
  "rawModel": {
    "about": "Gemini 3.8 Flash on tarkoitettu pitkäkestoisiin ohjelmistotekniikan tehtäviin, agenttiprosesseihin ja vaativaan tietotyöhön. Google kuvaa sitä Gemini 3.7 Flash -mallin jatkokehitykseksi, jossa painotetaan prosesseja, joiden ratkaisu ei pääty yhteen vastaukseen: malli palaa aineistoihin, käyttää työkaluja ja jatkaa vaiheketjua.\n\n### Analysoitavat aineistot\n\nGoogle ilmoittaa syötteiksi **tekstin, kuvat, videon, äänen ja PDF-tiedostot**. Ailoot API:n nykyisessä luettelossa tekstimenetelmien syötteeksi ilmoitetaan **teksti ja kuvat** ja tulosteeksi teksti. Video, ääni ja PDF eivät kuulu tähän syötevalikoimaan. Syötteen raja on **1 048 576 tokenia** ja tulosteen **65 536 tokenia**. Malli muodostaa tekstituloksen, joka voi sisältää ohjelmakoodia ja rakenteista tietoa. Kuvien ja äänen luominen ei kuulu tämän nimenomaisen version ominaisuuksiin.\n\n### Päättely ja työkalut\n\nTuetut Thinking-tasot ovat **`low`, `medium` ja `high`**. Googlen kuvaamassa perusmallin tilassa oletustaso on `medium`. Nämä arvot kuvaavat Googlen perusmallia; tila ja sen ohjausmahdollisuudet Ailoot API:n kautta riippuvat valitusta menetelmästä ja malliversiosta. Tasoa `minimal` ei tueta, ja se aiheuttaa virheen. Säädettävä panos auttaa valitsemaan tilan työvaiheen vaativuuden mukaan, mutta suurella panoksella malli käyttää toisinaan enemmän tokeneita tehtävän suorittamiseen.\n\nOminaisuuksiin kuuluvat funktiokutsut, koodin suoritus, rakenteiset vastaukset ja kontekstin välimuisti. Tarjolla on tiedostohaku, hakutuloksiin perustuva ankkurointi, Google Maps -palvelu ja verkko-osoitteiden sisällön lukeminen. Eräkäsittelyä tuetaan. Tietokoneen käyttöliittymän ohjaus on alustava ominaisuus; se ei tee kaikista mallin kutsutavoista täysimittaista tietokoneen ohjausta.\n\n### Käyttötarkoitus ja rajoitukset\n\nValmistaja painottaa ohjelmistotekniikkaa, agenttitehtäviä ja vaativia tiedonkäsittelyprosesseja. Pitkä konteksti mahdollistaa laajojen aineistojen lähettämisen ja työkaluominaisuudet useiden toisiinsa liittyvien vaiheiden järjestämisen. Nämä ominaisuudet kuvaavat mallin kykyjä; käytettävissä olevat vaihtoehdot ja syötteet riippuvat tuetusta kutsumenetelmästä.\n\nVersio julkaistiin vakaana syyskuussa 2026. Ilmoitettu tietojen aikaraja on maaliskuu 2026, mutta joillakin alueilla tiedot voivat olla tammikuun 2025 tasolla. Keksityt faktat, viiveet ja aikakatkaisut ovat mahdollisia. Laajempi päättely ei poista virheitä, eikä matala päättelypanos ole lupaus tietystä vastausajasta.",
    "alias_of": null,
    "aliases": [],
    "author": "Google",
    "ctx": 1048576,
    "formats": [
      "messages",
      "gemini"
    ],
    "id": "gemini-3.8-flash-medium",
    "input": [
      "text",
      "image"
    ],
    "kind": "text",
    "max_out": 65536,
    "methods": [
      {
        "cache_read": 0.075,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Keep all content blocks, thinking signatures and actual tool-use IDs. Assemble all SSE block deltas; a first text block is not the complete output.",
            "authentication": {
              "api_key_source": "AILOOT_API_KEY",
              "headers": [
                "x-api-key",
                "anthropic-version"
              ],
              "version_example": "2023-06-01"
            },
            "errors": [
              {
                "code": null,
                "condition": "Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo",
                "http_status": 400,
                "recovery": "Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Model context is not an output cap.",
              "A model-dependent field needs the exact published model profile; unspecified defaults/enums are not guessed.",
              "Tool calls propose actions; the client application returns actual observations with the returned call ID."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "create": {
                "http": "POST",
                "path": "/v1/messages"
              },
              "job_read": null,
              "mode": "synchronous_or_streamed",
              "unknown": "Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta."
            },
            "material_combinations": [
              {
                "mode": "text",
                "representation": "messages[].content tai type=text-lohko",
                "required_material": "UTF8-teksti"
              },
              {
                "availability": "Exact model input declaration and selected Source bridge required",
                "file_id_workflow": "No Ailoot upload/file-ID endpoint is introduced by this feed.",
                "mode": "text_plus_image",
                "representation": "{type:image,source:{type:base64,media_type,data}} tai lähde, jossa type=url"
              }
            ],
            "operation_modes": [
              "conversation",
              "function_tool_continuation",
              "streaming"
            ],
            "outputs": {
              "all_results": "Säilytä kaikki sisältölohkot, päättelyallekirjoitukset ja todelliset työkalukäytön ID:t. Kokoa kaikki SSE-lohkomuutokset; ensimmäinen tekstilohko ei ole koko tulos.",
              "family": "text",
              "fields": [
                {
                  "description": null,
                  "name": "id",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "model",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "content[]",
                  "type": "text|thinking|tool_use|other content block"
                },
                {
                  "description": null,
                  "name": "stop_reason",
                  "type": "string|null"
                },
                {
                  "description": null,
                  "name": "usage",
                  "type": "object"
                }
              ],
              "format": "json tai SSE"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "gemini-3.8-flash-medium"
                ],
                "enum_known": true,
                "name": "model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "min_items": 1,
                "name": "messages",
                "required": true,
                "type": "message[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "user",
                  "assistant"
                ],
                "enum_known": true,
                "name": "messages[].role",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "messages[].content",
                "required": true,
                "type": "string|content_block[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "system",
                "required": false,
                "type": "string|content_block[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "limit_scope": "valitun mallin/kortin täsmällinen yläraja",
                "minimum": 1,
                "name": "max_tokens",
                "required": true,
                "type": "integer"
              },
              {
                "availability": "source_interface",
                "default": false,
                "default_known": true,
                "enum": null,
                "enum_known": false,
                "name": "stream",
                "required": false,
                "type": "boolean"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "temperature",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "top_p",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "stop_sequences",
                "required": false,
                "type": "string[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools",
                "required": false,
                "type": "tool[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].name",
                "required": false,
                "type": "string",
                "when": "työkalu annettu"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].description",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].input_schema",
                "required": false,
                "type": "JSON_schema"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tool_choice",
                "required": false,
                "type": "object"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "thinking.type",
                "required": false,
                "type": "string"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "thinking.budget_tokens",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "output_config.effort",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "metadata",
                "required": false,
                "type": "object"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "cache_control",
                "required": false,
                "type": "object"
              }
            ],
            "profile_binding": "Exact existing Ailoot model and method; interface constraints below do not assert provider qualification.",
            "unsupported": []
          },
          "hints": [
            "Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä."
          ],
          "input": {
            "content_type": "application/json",
            "material_types": [
              "text",
              "image"
            ],
            "optional_controls": null,
            "required": [
              "model",
              "messages",
              "max_tokens"
            ],
            "text_file_material": "varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen"
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "POST",
            "path": "/v1/messages"
          },
          "operation_modes": [
            "messages"
          ],
          "output": {
            "family": [
              "text"
            ],
            "format": "JSON or supported SSE",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": 1048576,
        "examples": [
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}\"\nexport AILOOT_TEXT_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"model\": \"gemini-3.8-flash-medium\", \"max_tokens\": 1024, \"messages\": []}')\nf=Path(os.environ[\"AILOOT_TEXT_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose your actual UTF-8 source material\")\ntext=f.read_text(encoding=\"utf-8\")\nif not text.strip():raise SystemExit(\"Source material must contain text\")\np[\"messages\"]=[{\"role\":\"user\",\"content\":\"Summarize this material and quote supporting source passages.\\n\\n\"+text}]\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H \"x-api-key: $AILOOT_API_KEY\" -H 'anthropic-version: 2023-06-01' -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(\"result.json\").read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n",
            "label": "Use actual text material",
            "language": "bash"
          },
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}\"\nexport AILOOT_IMAGE_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"model\": \"gemini-3.8-flash-medium\", \"max_tokens\": 1024, \"messages\": [{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"Read labels and numbers in this image; flag unreadable text.\"}]}]}')\nimport base64\nf=Path(os.environ[\"AILOOT_IMAGE_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose an actual PNG JPEG or WebP image\")\nraw=f.read_bytes()\nmime=\"image/png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"image/jpeg\" if raw.startswith(b\"\\xff\\xd8\") else \"image/webp\" if raw[:4]==b\"RIFF\" and raw[8:12]==b\"WEBP\" else None\nif not mime:raise SystemExit(\"Use PNG JPEG or WebP\")\nb64=base64.b64encode(raw).decode()\np[\"messages\"][0][\"content\"].append({\"type\":\"image\",\"source\":{\"type\":\"base64\",\"media_type\":mime,\"data\":b64}})\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \\\n  -H \"x-api-key: $AILOOT_API_KEY\" -H 'anthropic-version: 2023-06-01' -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport json\nfrom pathlib import Path\nprint(json.dumps(json.loads(Path(\"result.json\").read_text()),ensure_ascii=False,indent=2))\nPY_RESULT\n",
            "label": "Use your actual image",
            "language": "bash"
          },
          {
            "code": "import anthropic\nimport os\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient = anthropic.Anthropic(base_url=\"https://api.ailoot.ai\", api_key=os.environ[\"AILOOT_API_KEY\"], max_retries=0)\nmsg = client.messages.create(\n    model=\"gemini-3.8-flash-medium\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Explain the difference between an observation and a hypothesis in three sentences.\"}],\n)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(msg.to_dict(mode=\"json\"))\n",
            "label": "Python · retained SDK call",
            "language": "python"
          },
          {
            "SDK_retry_proof": {
              "field": "maxRetries",
              "scope": "normalclient options; no provider/account/proxy switches",
              "source_urls": [
                "https://raw.githubusercontent.com/openai/openai-node/master/src/client.ts",
                "https://raw.githubusercontent.com/anthropics/anthropic-sdk-typescript/main/src/client.ts"
              ],
              "value": 0
            },
            "code": "import Anthropic from \"@anthropic-ai/sdk\";\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(\"Set AILOOT_API_KEY before making a request\");\nconst client = new Anthropic({ baseURL: \"https://api.ailoot.ai\", apiKey: process.env.AILOOT_API_KEY, maxRetries: 0 });\nconst msg = await client.messages.create({\n  model: \"gemini-3.8-flash-medium\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"Explain the difference between an observation and a hypothesis in three sentences.\" }],\n});\nimport { writeFileSync } from \"node:fs\";\n\nfunction saveResult(data, stem = \"result\") {\n  writeFileSync(stem + \".json\", JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) => {\n    const raw = Buffer.from(encoded, \"base64\");\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? \"png\" : raw[0]===255 && raw[1]===216 ? \"jpg\" : raw.subarray(0,4).toString()===\"RIFF\" && raw.subarray(8,12).toString()===\"WEBP\" ? \"webp\" : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(\"Saved\", file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(\"Content\", i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(\"Choice\", choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(\"Output\", i, JSON.stringify(item));\n    if (item.type === \"image_generation_call\" && item.result) saveBlob(item.result, item.output_format || \"bin\", `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(\"Candidate/part\", ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"})[mime] || \"bin\";\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(msg);\n",
            "label": "Node.js · retained SDK call",
            "language": "js"
          },
          {
            "code": "import anthropic,os\nfrom pathlib import Path\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient=anthropic.Anthropic(base_url=\"https://api.ailoot.ai\",api_key=os.environ[\"AILOOT_API_KEY\"],max_retries=0)\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nwith client.messages.stream(model='gemini-3.8-flash-medium',max_tokens=1024,messages=[{\"role\":\"user\",\"content\":\"Explain observations and hypotheses in three sentences.\"}]) as stream:\n    with Path(\"stream-events.jsonl\").open(\"w\",encoding=\"utf-8\") as log:\n        for event in stream:\n            payload=event.to_dict(mode=\"json\")\n            log.write(json.dumps(payload,ensure_ascii=False)+\"\\n\"); log.flush()\n            print(json.dumps(payload,ensure_ascii=False))\n    final=stream.get_final_message()\n    save_result(final.to_dict(mode=\"json\"),\"stream-result\")\n",
            "label": "Python streaming · complete final message",
            "language": "python"
          }
        ],
        "family": "anthropic",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "messages",
        "http": "POST",
        "img_in": null,
        "img_out": null,
        "in": 0.75,
        "input": [
          "text",
          "image"
        ],
        "label": "Anthropic Messages",
        "max_out": 65536,
        "max_tool_calls": null,
        "out": 3.75,
        "output": [
          "text"
        ],
        "path": "/v1/messages",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 3.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.075,
                "amount_unit": "usd_per_million_tokens",
                "key": "cache_read",
                "label": "Cache read",
                "side": "in"
              }
            ]
          }
        ],
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "token",
        "units": []
      },
      {
        "cache_read": 0.075,
        "cache_write": null,
        "cache_write_1h": null,
        "cache_write_5m": null,
        "conditional_meter": null,
        "contract": {
          "data": {
            "all_results": "Keep all candidates and parts, including function calls, thought signatures and usage; assemble stream chunks in order.",
            "authentication": {
              "api_key_source": "AILOOT_API_KEY",
              "header": "x-goog-api-key"
            },
            "errors": [
              {
                "code": null,
                "condition": "Virheelliset pakolliset kentät, aineiston esitysmuoto tai parametrin arvo",
                "http_status": 400,
                "recovery": "Korjaa ilmoitetut kentät ennen uutta luontipyyntöä.",
                "type": "invalid_request_error"
              }
            ],
            "hints": [
              "Model context is not an output cap.",
              "A model-dependent field needs the exact published model profile; unspecified defaults/enums are not guessed.",
              "Tool calls propose actions; the client application returns actual observations with the returned call ID."
            ],
            "ignored_fields": [],
            "lifecycle": {
              "create": {
                "http": "POST",
                "path": "/v1beta/models/{model}:generateContent"
              },
              "job_read": null,
              "mode": "synchronous_or_streamed",
              "unknown": "Säilytä pyyntöjen/vastausten ID:t ja otsakkeet. Yleistä tekstityön haku-URL:ää ei anneta."
            },
            "material_combinations": [
              {
                "mode": "text",
                "representation": "contents[].parts[].text",
                "required_material": "UTF8-teksti"
              },
              {
                "availability": "Exact model input declaration and selected Source bridge required",
                "file_id_workflow": "No Ailoot upload/file-ID endpoint is introduced by this feed.",
                "mode": "text_plus_image",
                "representation": "parts[].inlineData={mimeType,data}"
              }
            ],
            "operation_modes": [
              "conversation",
              "function_tool_continuation",
              "generate_content"
            ],
            "outputs": {
              "all_results": "Säilytä kaikki ehdokkaat ja osat, mukaan lukien funktiokutsut, päättelyallekirjoitukset ja käyttötiedot; kokoa virran lohkot järjestyksessä.",
              "family": "text",
              "fields": [
                {
                  "description": null,
                  "name": "responseId",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "modelVersion",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "candidates[].content.parts[]",
                  "type": "text|inlineData|functionCall|other part"
                },
                {
                  "description": null,
                  "name": "candidates[].finishReason",
                  "type": "string"
                },
                {
                  "description": null,
                  "name": "usageMetadata",
                  "type": "object"
                }
              ],
              "format": "json tai tuettu virtakäsittely"
            },
            "parameters": [
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "gemini-3.8-flash-medium"
                ],
                "enum_known": true,
                "name": "path.model",
                "required": true,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "min_items": 1,
                "name": "contents",
                "required": true,
                "type": "content[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": [
                  "user",
                  "model"
                ],
                "enum_known": true,
                "name": "contents[].role",
                "required": false,
                "type": "string"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "contents[].parts",
                "required": true,
                "type": "part[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "systemInstruction",
                "required": false,
                "type": "content"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "minimum": 1,
                "name": "generationConfig.maxOutputTokens",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.temperature",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.topP",
                "required": false,
                "type": "number"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.topK",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.stopSequences",
                "required": false,
                "type": "string[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.thinkingConfig.includeThoughts",
                "required": false,
                "type": "boolean"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "generationConfig.thinkingConfig.thinkingBudget",
                "required": false,
                "type": "integer"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "tools[].functionDeclarations",
                "required": false,
                "type": "function_declaration[]"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "toolConfig.functionCallingConfig.mode",
                "required": false,
                "type": "string"
              },
              {
                "availability": "model_dependent",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "safetySettings",
                "required": false,
                "type": "object[]"
              },
              {
                "availability": "source_interface",
                "default": null,
                "default_known": false,
                "enum": null,
                "enum_known": false,
                "name": "sessionId",
                "required": false,
                "type": "string"
              }
            ],
            "profile_binding": "Exact existing Ailoot model and method; interface constraints below do not assert provider qualification.",
            "unsupported": []
          },
          "hints": [
            "Menetelmien rakenteet ja ID:t ovat täsmällisiä; toimittajan kyvykkyys on erillinen pyynnön hyväksymisestä."
          ],
          "input": {
            "content_type": "application/json",
            "material_types": [
              "text",
              "image"
            ],
            "optional_controls": null,
            "required": [
              "contents"
            ],
            "text_file_material": "varsinainen UTF-8-sisältö lisätään tekstinä; tiedostojen ID- tai URLs-arvot tarvitsevat erillisen täsmällisen tuen"
          },
          "lifecycle": {
            "mode": "exact retained published method"
          },
          "method": {
            "http": "POST",
            "path": "/v1beta/models/{model}:generateContent"
          },
          "operation_modes": [
            "gemini"
          ],
          "output": {
            "family": [
              "text"
            ],
            "format": "JSON or supported SSE",
            "multioutputs": "retain every actual response output"
          }
        },
        "ctx": null,
        "examples": [
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_TEXT_FILE:?Set your actual UTF-8 source-material file}\"\nexport AILOOT_TEXT_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"contents\": []}')\nf=Path(os.environ[\"AILOOT_TEXT_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose your actual UTF-8 source material\")\ntext=f.read_text(encoding=\"utf-8\")\nif not text.strip():raise SystemExit(\"Source material must contain text\")\np[\"contents\"]=[{\"role\":\"user\",\"parts\":[{\"text\":\"Summarize this material and quote supporting source passages.\\n\\n\"+text}]}]\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H \"x-goog-api-key: $AILOOT_API_KEY\" -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(json.loads(Path(\"result.json\").read_text(encoding=\"utf-8\")))\nPY_RESULT\n",
            "label": "Use actual text material",
            "language": "bash"
          },
          {
            "code": "set -eu\n: \"${AILOOT_API_KEY:?Set your Ailoot API key}\"\n: \"${AILOOT_IMAGE_FILE:?Set your actual PNG JPEG or WebP image}\"\nexport AILOOT_IMAGE_FILE\npython3 - <<'PY_REQUEST'\nimport json,os\nfrom pathlib import Path\np=json.loads('{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"Read labels and numbers in this image; flag unreadable text.\"}]}]}')\nimport base64\nf=Path(os.environ[\"AILOOT_IMAGE_FILE\"])\nif not f.is_file():raise SystemExit(\"Choose an actual PNG JPEG or WebP image\")\nraw=f.read_bytes()\nmime=\"image/png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"image/jpeg\" if raw.startswith(b\"\\xff\\xd8\") else \"image/webp\" if raw[:4]==b\"RIFF\" and raw[8:12]==b\"WEBP\" else None\nif not mime:raise SystemExit(\"Use PNG JPEG or WebP\")\nb64=base64.b64encode(raw).decode()\np[\"contents\"][0][\"parts\"].append({\"inlineData\":{\"mimeType\":mime,\"data\":b64}})\nPath(\"request.json\").write_text(json.dumps(p,ensure_ascii=False))\nPY_REQUEST\ncurl --fail-with-body --silent --show-error https://api.ailoot.ai/v1beta/models/gemini-3.8-flash-medium:generateContent \\\n  -H \"x-goog-api-key: $AILOOT_API_KEY\" -H 'Content-Type: application/json' \\\n  --data-binary @request.json -D response-headers.txt -o result.json\npython3 - <<'PY_RESULT'\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(json.loads(Path(\"result.json\").read_text(encoding=\"utf-8\")))\nPY_RESULT\n",
            "label": "Use your actual image",
            "language": "bash"
          },
          {
            "code": "from google import genai\nfrom google.genai import types\nimport os\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient = genai.Client(\n    api_key=os.environ[\"AILOOT_API_KEY\"],\n    http_options=types.HttpOptions(base_url=\"https://api.ailoot.ai\"),\n)\nresp = client.models.generate_content(model=\"gemini-3.8-flash-medium\", contents=\"Explain the difference between an observation and a hypothesis in three sentences.\")\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\nsave_result(resp.to_json_dict())\n",
            "label": "Python · retained SDK call",
            "language": "python"
          },
          {
            "code": "import { GoogleGenAI } from \"@google/genai\";\n\nif (!process.env.AILOOT_API_KEY?.trim()) throw new Error(\"Set AILOOT_API_KEY before making a request\");\nconst ai = new GoogleGenAI({ apiKey: process.env.AILOOT_API_KEY, httpOptions: { baseUrl: \"https://api.ailoot.ai\" } });\nconst resp = await ai.models.generateContent({ model: \"gemini-3.8-flash-medium\", contents: \"Explain the difference between an observation and a hypothesis in three sentences.\" });\nimport { writeFileSync } from \"node:fs\";\n\nfunction saveResult(data, stem = \"result\") {\n  writeFileSync(stem + \".json\", JSON.stringify(data, null, 2));\n  console.log(JSON.stringify(data, null, 2));\n  const saveBlob = (encoded, suffix, label) => {\n    const raw = Buffer.from(encoded, \"base64\");\n    const ext = raw.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])) ? \"png\" : raw[0]===255 && raw[1]===216 ? \"jpg\" : raw.subarray(0,4).toString()===\"RIFF\" && raw.subarray(8,12).toString()===\"WEBP\" ? \"webp\" : suffix;\n    const file = `${stem}-${label}.${ext}`;\n    writeFileSync(file, raw); console.log(\"Saved\", file);\n  };\n  for (const [i, block] of (data.content || []).entries()) console.log(\"Content\", i, JSON.stringify(block));\n  for (const choice of data.choices || []) console.log(\"Choice\", choice.index, JSON.stringify(choice.message || choice.delta || {}));\n  for (const [i, item] of (data.output || []).entries()) {\n    console.log(\"Output\", i, JSON.stringify(item));\n    if (item.type === \"image_generation_call\" && item.result) saveBlob(item.result, item.output_format || \"bin\", `output-${i}`);\n  }\n  for (const [ci, candidate] of (data.candidates || []).entries()) {\n    for (const [pi, part] of (candidate.content?.parts || []).entries()) {\n      console.log(\"Candidate/part\", ci, pi, JSON.stringify(part));\n      const blob = part.inlineData || part.inline_data;\n      if (blob?.data) {\n        const mime = blob.mimeType || blob.mime_type;\n        const suffix = ({\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"})[mime] || \"bin\";\n        saveBlob(blob.data, suffix, `candidate-${ci}-part-${pi}`);\n      }\n    }\n  }\n}\n\nsaveResult(resp);\n",
            "label": "Node.js · retained SDK call",
            "language": "js"
          },
          {
            "code": "from google import genai\nfrom google.genai import types\nimport os\nfrom pathlib import Path\n\nif not os.environ.get(\"AILOOT_API_KEY\", \"\").strip(): raise SystemExit(\"Set AILOOT_API_KEY before making a request\")\nclient=genai.Client(api_key=os.environ[\"AILOOT_API_KEY\"],http_options=types.HttpOptions(base_url=\"https://api.ailoot.ai\"))\nimport base64, json\nfrom pathlib import Path\n\ndef save_result(data, stem=\"result\"):\n    # Keep every field, including usage, IDs, reasoning and tool requests.\n    Path(stem + \".json\").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n    print(json.dumps(data, ensure_ascii=False, indent=2))\n    def save_blob(encoded, suffix, label):\n        raw = base64.b64decode(encoded, altchars=b\"-_\", validate=True)\n        ext = \"png\" if raw.startswith(b\"\\x89PNG\\r\\n\\x1a\\n\") else \"jpg\" if raw.startswith(b\"\\xff\\xd8\") else \"webp\" if raw[:4] == b\"RIFF\" and raw[8:12] == b\"WEBP\" else suffix\n        file = Path(stem + \"-\" + label + \".\" + ext)\n        file.write_bytes(raw)\n        print(\"Saved\", file)\n    for index, block in enumerate(data.get(\"content\") or []):\n        print(\"Content\", index, json.dumps(block, ensure_ascii=False))\n    for choice in data.get(\"choices\") or []:\n        print(\"Choice\", choice.get(\"index\"), json.dumps(choice.get(\"message\", choice.get(\"delta\", {})), ensure_ascii=False))\n    for index, item in enumerate(data.get(\"output\") or []):\n        print(\"Output\", index, json.dumps(item, ensure_ascii=False))\n        if item.get(\"type\") == \"image_generation_call\" and item.get(\"result\"):\n            save_blob(item[\"result\"], item.get(\"output_format\") or \"bin\", \"output-\" + str(index))\n    for ci, candidate in enumerate(data.get(\"candidates\") or []):\n        for pi, part in enumerate((candidate.get(\"content\") or {}).get(\"parts\") or []):\n            print(\"Candidate/part\", ci, pi, json.dumps(part, ensure_ascii=False))\n            blob = part.get(\"inlineData\") or part.get(\"inline_data\")\n            if blob and blob.get(\"data\"):\n                mime = blob.get(\"mimeType\") or blob.get(\"mime_type\")\n                suffix = {\"image/png\":\"png\", \"image/jpeg\":\"jpg\", \"image/webp\":\"webp\", \"audio/wav\":\"wav\", \"audio/mpeg\":\"mp3\", \"video/mp4\":\"mp4\"}.get(mime, \"bin\")\n                save_blob(blob[\"data\"], suffix, \"candidate-\" + str(ci) + \"-part-\" + str(pi))\n\ncount=0\nwith Path(\"stream-events.jsonl\").open(\"w\",encoding=\"utf-8\") as log:\n    for chunk in client.models.generate_content_stream(model='gemini-3.8-flash-medium',contents=\"Explain observations and hypotheses in three sentences.\"):\n        payload=chunk.to_json_dict()\n        log.write(json.dumps(payload,ensure_ascii=False)+\"\\n\"); log.flush()\n        save_result(payload,\"stream-chunk-\"+str(count))\n        count+=1\n",
            "label": "Python streaming · retain all chunks",
            "language": "python"
          }
        ],
        "family": "gemini",
        "fast_multiplier": null,
        "flex_multiplier": null,
        "fmt": "gemini",
        "http": "POST",
        "img_in": null,
        "img_out": null,
        "in": 0.75,
        "input": [
          "text",
          "image"
        ],
        "label": "Gemini generateContent",
        "max_out": null,
        "max_tool_calls": null,
        "out": 3.75,
        "output": [
          "text"
        ],
        "path": "/v1beta/models/{model}:generateContent",
        "pricing_profiles": [
          {
            "dimensions": {},
            "label": "Core",
            "units": [
              {
                "amount": 0.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "in",
                "label": "Input",
                "side": "in"
              },
              {
                "amount": 3.75,
                "amount_unit": "usd_per_million_tokens",
                "key": "out",
                "label": "Output",
                "side": "out"
              },
              {
                "amount": 0.075,
                "amount_unit": "usd_per_million_tokens",
                "key": "cache_read",
                "label": "Cache read",
                "side": "in"
              }
            ]
          }
        ],
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core",
        "status_reads": [],
        "tiers": [],
        "tool_prices": null,
        "unit": "token",
        "units": []
      }
    ],
    "model_aliases": [
      {
        "canonical_model_id": "gemini-3.8-flash-medium",
        "request_model_id": "gemini-3.8-flash-medium",
        "route_label": "Core"
      }
    ],
    "name": "Gemini 3.8 Flash Medium",
    "price": {
      "in": 0.75,
      "in_label": null,
      "out": 3.75,
      "out_label": null,
      "sort_in": 0.75,
      "sort_out": 3.75,
      "varies": false
    },
    "short": "Googlen multimodaalinen malli pitkäkestoiseen ohjelmistotekniikkaan, autonomisiin agentteihin ja vaativaan tietotyöhön."
  },
  "renderer_schema": {
    "method_order": "Original DTO methods order; every exact route/format/path/caller survives.",
    "prices": "Original public DTO fields and original native display HTML; no flattened or normalized offers."
  },
  "representation": "exact-public-dto-and-native-renderer-html",
  "representationNotes": {
    "current_reference": {
      "about_json_pointer": "/aboutHtml",
      "methods": [
        {
          "contract_json_pointer": "/methods/0/rawMethod/contract",
          "html_json_pointer": "/methods/0/html",
          "method_ordinal": 0
        },
        {
          "contract_json_pointer": "/methods/1/rawMethod/contract",
          "html_json_pointer": "/methods/1/html",
          "method_ordinal": 1
        }
      ],
      "role": "current-semantic-reference"
    },
    "raw_input": {
      "examples_role": "historical-input-not-current-ready-examples",
      "json_pointers": [
        "/rawModel",
        "/methods/0/rawMethod",
        "/methods/1/rawMethod"
      ],
      "role": "historical-owner-input"
    },
    "schema": "ailoot-native-model-representations-v1"
  },
  "schema": "ailoot-static-model-facts-v1",
  "schema_version": 1,
  "shortText": "Googlen multimodaalinen malli pitkäkestoiseen ohjelmistotekniikkaan, autonomisiin agentteihin ja vaativaan tietotyöhön.",
  "source": {
    "audit_sha256": "2e00086bcbfc28e64d0cebe97aa47c17d8d5618963027f8ffb9dc6123d7d25b1",
    "bridge_map_sha256": "1125275768b9636fc8461bc7da5061239a81ddfe508e2557843ca42c58ab0036",
    "raw_model_json_sha256": "98c9caccf231525d274d0801e2776d673a4c869d4185bd31a26a5e98481b2ac3",
    "renderer_sha256": "303a59603e2bc29ba8fda690e95fd32cec68de223d92e26054a88babff801dd7"
  },
  "sourceRevision": "dbb322bc9d1eef19b32ea5b3a10cfa6c13e845340384900d34decba86cb9969a"
}
