Ga naar inhoud

Scripts via de API

Het concept achter tools staat in Tools.

Een script is een eigen programma dat het model als één tool aanroept. Je uploadt één keer een klein pakket — een Python- of Node-entrypoint, de bestanden die het nodig heeft en de argumenten die het neemt — en Core biedt het het model aan als script__<naam>. Roept het model het aan, dan draait Core het pakket op de computer van de beurt, met de argumenten van het model, en geeft terug wat het afdrukte en de bestanden die het schreef. Het model ziet je code nooit: het ziet een naam, een beschrijving en een schema voor de argumenten.

Gebruik een script als het model een getest programma moet pakken in plaats van de code elke beurt opnieuw te schrijven. "Maak een presentatie in onze huisstijl" wordt één aanroep van script__huisstijl_presentatie met de dia's als argumenten, gedraaid op het sjabloon dat je één keer uploadde.

Wat je sleutel nodig heeft

  1. De capability tooling, om scripts te registreren en aan te bieden.
  2. De capability computer, om ze te draaien. Je organisatie moet computer toestaan.
  3. files als het model met de bijlagen van een beurt moet werken of als je bestanden via een upload registreert, en artifacts als je de bestanden die een script schrijft terug wilt krijgen.

Een sleutel heeft de systeemtool computer onder tooling.system_tools niet nodig. Die schakelaar zet de drie shell-tools van Computers aan; zonder die schakelaar draait een sleutel je scripts en krijgt hij nooit een shell in handen.

{
  "name": "Presentaties",
  "capabilities": {
    "tooling": {},
    "computer": {},
    "files": {},
    "artifacts": {}
  }
}

Je installatie moet computers draaien voor je organisatie. Doet hij dat niet, dan weigert Core een verzoek dat een script noemt met "This tool is not configured on this deployment.", nog voordat het model draait; de body draagt "reason_code": "computer_not_configured".

Een script registreren

POST /scripts maakt het script en zijn versie 1:

curl -s -X POST "$CORE_URL/scripts" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d @huisstijl_presentatie.json
{
  "name": "huisstijl_presentatie",
  "description": "Maak een PowerPoint-presentatie in de huisstijl van het bedrijf. Gebruik dit als de gebruiker om dia's vraagt.",
  "entrypoint": ["python3", "main.py"],
  "parameters": {
    "type": "object",
    "properties": {
      "theme": { "type": "string", "description": "Thema van de presentatie" },
      "title": { "type": "string", "description": "Titel van de eerste dia" },
      "slides": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "heading": { "type": "string" },
            "bullets": { "type": "array", "items": { "type": "string" } }
          },
          "required": ["heading"]
        }
      }
    },
    "required": ["title", "slides"]
  },
  "files": [
    { "path": "main.py", "content": "import json, os\nfrom pptx import Presentation\n..." },
    { "path": "sjabloon.pptx", "file_id": "file_8Kd2..." }
  ],
  "packages": [
    { "ecosystem": "pypi", "name": "python-pptx", "version": "1.0.2" }
  ],
  "timeout_seconds": 60,
  "labels": { "team": "marketing" }
}
Veld Wat erin staat
name kleine letters, cijfers, - en _, hoogstens 48 tekens. Het model ziet script__<naam>. De naam verandert nooit: policyregels, verbruiksregels en de audittrail leggen hem vast. Uniek binnen je organisatie; een dubbele naam is 409
description wat de tool doet en wanneer het model hem moet gebruiken, hoogstens 1024 tekens
entrypoint het programma dat draait, als lijst van 1 tot 16 argumenten, zoals ["python3", "main.py"] of ["node", "index.js"]. Nooit een shell-regel: pipes, && en omleidingen werken niet
parameters een JSON Schema-object (Draft 2020-12, hoogstens 64 KiB) waaraan de argumenten van het model moeten voldoen. Lijsten en geneste objecten mogen. Laat het weg voor een script zonder argumenten
files alle bestanden van het pakket, zie Bestanden
packages de goedgekeurde bibliotheken die het pakket nodig heeft, zie Pakketten
timeout_seconds optioneel: hoe lang één aanroep mag duren. Kan de eigen limiet van de aanroepende sleutel (computer.exec_timeout_seconds) alleen inkorten; laat het weg om die limiet te nemen
labels, metadata je eigen indeling van het script, die policyregels over tools lezen, en een vrij document dat Core bewaart en nooit leest. Voor een verzoek dat een persoon noemt, beslissen de regels over script__<naam> ook of GET /scripts het script toont en of het een versie mag krijgen of verwijderd mag worden (Registraties)

Core antwoordt 201 met het script en een header Location. GET /scripts geeft je scripts, elk met de velden en het nummer van de laatste versie; GET /scripts/{script_id} geeft er één.

Bestanden

Elk item van files heeft een path en precies één van twee bronnen:

  • content: de UTF-8-tekst van het bestand, in de body. Gebruik dit voor broncode.
  • file_id: een bestand dat je eerst uploadde met POST /files (Bestanden). Gebruik dit voor binaire bestanden zoals een sjabloon of een lettertype, en voor alles wat groot is. Core kopieert de upload in de versie, dus de upload later weghalen laat de versie heel. Je sleutel heeft files nodig en moet die upload mogen lezen.

Een pad is relatief, zoals main.py of lib/deck.py, hoogstens 255 tekens, zonder .., backslash of / vooraan. Een pakket heeft hoogstens 200 bestanden en 20 MiB samen. Een body is hoogstens 1 MiB, dus grotere bestanden gaan via file_id.

GET /scripts/{script_id}/versions/{version}/files/{path} geeft de bytes van één bestand, met de SHA-256-digest van het bestand als ETag.

Wat het script meekrijgt

De entrypoint draait in de eigen map van het pakket, zodat main.py zijn eigen modules en bestanden vindt. Het leest de argumenten van het model als één JSON-object, van standaardinvoer of uit het bestand dat de omgeving noemt:

Variabele Wat die noemt
ARTIFIC_ARGUMENTS het bestand met de argumenten, dezelfde JSON als op standaardinvoer
ARTIFIC_OUTPUTS een lege map voor deze aanroep. Elk bestand dat het script direct hierin schrijft, komt terug
ARTIFIC_INPUTS /workspace/inputs, waar de bijlagen van de beurt staan, als <bestands-id>/<bestandsnaam>

Een kleine main.py:

import json
import os
from pptx import Presentation

args = json.load(open(os.environ["ARTIFIC_ARGUMENTS"]))
deck = Presentation("sjabloon.pptx")
# ... een dia per item van args["slides"] ...
deck.save(os.path.join(os.environ["ARTIFIC_OUTPUTS"], "presentatie.pptx"))
print(f"{len(args['slides'])} dia's geschreven")

Een nieuwe versie

Een versie verandert nooit meer als hij geschreven is. Wil je iets wijzigen — code, bestanden, beschrijving, parameters, pakketten, time-out — stuur dan het hele pakket opnieuw:

curl -s -X POST "$CORE_URL/scripts/$SCRIPT_ID/versions" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d @huisstijl_presentatie_v2.json

De body heeft de velden van POST /scripts zonder name. Bestanden die je weglaat, zitten niet in de nieuwe versie: een versie is één pakket dat als geheel getest is. Core antwoordt 201 met de nieuwe versie. Is de body bestand voor bestand gelijk aan de laatste versie, dan wordt niets geschreven en antwoordt Core 200 met de laatste. labels en metadata in de body vervangen die van het script; laat je ze weg, dan blijven ze.

GET /scripts/{script_id}/versions geeft de versies, nieuwste eerst, en GET /scripts/{script_id}/versions/{version} geeft er één.

Een beheerder kan een versie ook als concept opslaan, in de console of de API ervan. Je sleutel ziet een concept niet: het script leest als zijn gepubliceerde versie, een beurt zonder version draait die, en wie het nummer van het concept vastzet, krijgt dezelfde weigering als bij een versie die niet bestaat. Een script met alleen een concept is voor je sleutel geen script en geen tool tot het gepubliceerd is.

DELETE /scripts/{script_id} verwijdert het script met al zijn versies en bestanden en antwoordt 204. Zolang een agent het script noemt, is verwijderen 409 met een lijst van die agents; haal het script daar eerst weg.

Aanbieden aan het model

Noem het script zoals elke andere tool:

{
  "model": "<een model-id>",
  "input": "Maak een presentatie van vijf dia's over onze cijfers van Q3.",
  "tools": [{ "type": "tool", "name": "script__huisstijl_presentatie" }]
}

Zonder version neemt de beurt de laatste versie. Zet een versie vast om een beurt op code te houden die je getest hebt:

{ "type": "tool", "name": "script__huisstijl_presentatie", "version": 2 }

Een versie die niet bestaat, wordt geweigerd op het veld version van dat item. De versie die een beurt koos, wordt bij het antwoord bewaard, zodat de latere rondes van een achtergrondrun dezelfde versie aanroepen.

Een script past ook overal waar verder een toolnaam past:

  • Een toolset bevat het op naam of via een patroon, zoals script__*. Een toolset volgt altijd de laatste versie.
  • Een alias geeft het een tweede naam en legt argumenten vast die het model nooit ziet, zoals alias__directie_presentatie met {"theme": "directie"} vast. Een alias kan een argument ook vastzetten op een bestand van jou: het script krijgt dan het pad van een kopie op zijn computer, onder /workspace/.calls/, en de kopie verdwijnt zodra het script klaar is (Een argument vastzetten op een bestand).
  • Een agent noemt het in zijn tools.

De policy van je sleutel beslist op naam: de regels over Tools moeten script__<naam> toestaan, zowel bij het aanbieden als opnieuw wanneer het model de tool aanroept. Een sleutel zonder tooling of computer die een script noemt, wordt geweigerd; in een toolset valt het script voor die sleutel weg. In een geneste agentbeurt kan een script niet: net als de computer-tools heeft het een eigen beurt nodig.

GET /tools/script__huisstijl_presentatie geeft het script zoals het model het ziet: de naam, de beschrijving en parameters van de laatste versie, en de labels.

Een script kan op de achtergrond draaien. Stuur background mee met het script of een nieuwe versie, zoals bij een API-koppeling, en het model mag het als taak starten: het draait dan op een eigen computer en het resultaat komt later in de thread terug. Zie Een tool op de achtergrond draaien.

Wat een aanroep doet

  1. Eerst worden de argumenten gecontroleerd. Argumenten die niet aan parameters voldoen, krijgen Tool arguments were not valid. als antwoord, met het pad van het eerste foute argument en de regel die het brak, zodat het model zichzelf kan verbeteren. Er draait niets.
  2. Het script draait op de computer van de beurt. De eerste computeraanroep van een antwoord maakt de computer, met de bijlagen van de beurt erin gekopieerd; elke volgende script- of shell-aanroep in hetzelfde antwoord gebruikt dezelfde machine, één aanroep tegelijk, in de volgorde waarin het model ze schreef. Zo kan het ene script lezen wat het andere schreef. Core controleert voor elke aanroep of het pakket op de computer precies de versie is, en schrijft het opnieuw als er iets aan veranderd is.
  3. De entrypoint draait onder één time-out: de kortste van timeout_seconds van de versie, computer.exec_timeout_seconds van je sleutel en de limiet van de installatie. Het model kan die niet verlengen.
  4. Het model krijgt de exitcode, standaarduitvoer en standaardfout terug, samen afgekapt op 32 KiB, gevolgd door de bestanden die de aanroep maakte:

    exit_code: 0
    stdout:
    5 dia's geschreven
    stderr:
    
    files:
    presentatie.pptx: kept as an artifact
    
  5. Elk bestand dat direct in ARTIFIC_OUTPUTS staat, wordt een artefact van je sleutel, hoogstens 10 per aanroep en 25 MiB per stuk. Een bestand boven die grenzen, een submap, een link, en elk bestand voor een sleutel zonder artifacts staat erbij als left on the computer. Bestanden die ergens anders staan, blijven op de computer tot het antwoord klaar is.

De uitvoer is onbetrouwbare toolinhoud, zoals elk toolresultaat (Vertrouwen in toolresultaten). Komt een aanroep niet op eigen kracht terug, dan leest het model een van de vaste zinnen van Core:

Wat er gebeurde Wat het model te horen krijgt Status van de aanroep
de argumenten voldoen niet aan parameters Tool arguments were not valid. met het pad en de regel — er wordt geen computer gemaakt error
het script stopt met een andere exitcode dan 0 de exitcode en de uitvoer, zoals hierboven error, executor_failed
de time-out verloopt wat het tot dan toe afdrukte, met bovenaan timed out after <n> seconds error, timeout
de versie noemt een pakket dat is ingetrokken This script needs a package that is no longer approved: <ecosystem> <name> <version>. — er wordt geen computer gemaakt error, executor_failed
je sleutel mag de regio waarin de computer draait niet bereiken Denied by policy. — er wordt geen computer gemaakt denied
de computer zou internet bereiken en je beleid beperkt waar gegevens heen mogen, of je sleutel verbergt persoonsgegevens, of je organisatie heeft computer_internet niet aangezet Denied by policy. — er wordt geen computer gemaakt voor de aanroep denied
de computer kon niet gemaakt of bereikt worden Computer is unavailable. error

Geen van deze beëindigt de beurt; het model kan verder.

Een script rechtstreeks aanroepen

Test een script voordat een model het gebruikt, met de argumenten die een model zou sturen:

curl -s -X POST "$CORE_URL/tools/script__huisstijl_presentatie/call" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"arguments": {"title": "Q3", "slides": [{"heading": "Omzet"}]}, "version": 2}'

Het antwoord is het object tool_call van Een tool rechtstreeks aanroepen: status, error_code, text met precies wat het model zou lezen, en de bestanden in outputs, base64 als je sleutel artifacts heeft en ze passen. Laat version weg om de laatste te draaien.

Een rechtstreekse aanroep maakt een computer voor die ene aanroep en ruimt hem op als de aanroep terugkomt. Die computer komt op je sleutel zoals elke andere, dus een proefdraai kost sandboxtijd.

Geen netwerk

Een script draait zonder netwerk: het bereikt het internet niet, je eigen systemen niet en ook geen pakketindex. Alles wat het nodig heeft, reist mee: zijn bestanden, de pakketten die Core ervoor installeert en de bijlagen van de beurt. Heeft een script gegevens van elders nodig, dan krijgt het die als argument of bijlage, of werkt het samen met een API-koppeling die het model eerst aanroept.

Een omgeving waarvan de beheerder computers aanbiedt die internet bereiken, is de uitzondering, voor een organisatie die computer_internet heeft aangezet, net als elke organisatie erboven: een script kan daar verbinding maken met de buitenwereld en zijn argumenten en bestanden overal heen sturen. Reken er niet op. Zonder die schakelaar draait het script zonder netwerk, of krijgt het geen computer als de omgeving alleen open computers heeft. Ook mét de schakelaar krijg je zo'n computer niet als je beleid toegestane regio's of leveranciers noemt, de hosts beperkt die het mag bereiken, of eist dat persoonsgegevens verborgen worden, of als je sleutel persoonsgegevens verbergt. Een organisatie die toegestane hosts heeft ingesteld, wordt ook geweigerd. Een regio-uitzondering verandert dat niet; elke scriptaanroep antwoordt Denied by policy..

Waar de omgeving de egress-proxy van Core draait, krijgt zo'n script de opdracht die te gebruiken, en het verkeer dat erdoor gaat, wordt vastgelegd -- host, bytes, tijd -- en, waar de omgeving een limiet instelt, per organisatie begrensd, zoals voor elke computer. Verkeer dat om de proxy heen gaat, bereikt het internet nog steeds, en wordt niet vastgelegd, niet begrensd en niet getoetst aan de blokkeerlijst of de regel voor privéadressen. De toegangsgegevens van de proxy staan in de omgeving van het script; een script dat ze afdrukt, zet ze in zijn uitvoer, en daarmee in de beurt en haar trace.

Pakketten

Een script kan alleen bibliotheken importeren die goedgekeurd zijn. Er zijn drie herkomsten, die GET /packages samen geeft, elk gemarkeerd met approval:

approval Wat het is Wie beslist
image een bibliotheek die al in de sandbox-image zit, zoals python-pptx of pandas (Wat de sandbox-image meebrengt) het platform: elke release brengt één image mee, en de lijst volgt die
deployment een bestand dat je operator goedkeurde voor elke organisatie op de installatie je operator; jij leest het, je kunt het niet wijzigen. Als goedkeurder staat er operator
organisation een bestand dat je organisatie goedkeurde voor haar eigen scripts een beheerder van je organisatie, of een sleutel met management

Bibliotheken uit de image kun je importeren zonder ze te noemen. Elk ander pakket moet in packages van de versie staan, als {ecosystem, name, version} met pypi of npm en de exacte versie. Bij het schrijven van de versie zoekt Core elk pakket op — eerst in de lijst van de installatie, dan in die van je organisatie — en legt vast via welke goedkeuring het gevonden werd en wat de SHA-256-digest van het goedgekeurde bestand is:

{ "ecosystem": "pypi", "name": "python-pptx", "version": "1.0.2", "approval": "image", "sha256": null }

Een script dat je uit een bundel installeerde, kan een vierde waarde tonen, bundle: een pakket dat alleen de uitgever goedkeurde, dat je met het installeren accepteerde en dat alleen voor die kopie geldt (Pakketten in een bundel).

Noem elk pakket, afhankelijkheden inbegrepen. Core installeert de bestanden offline en lost geen afhankelijkheden op: een bibliotheek die je pakket nodig heeft, en elke bibliotheek die díe weer nodig heeft, moet elk goedgekeurd en genoemd zijn. Een vergeten afhankelijkheid faalt bij de eigen import van het script, wat een rechtstreekse aanroep meteen laat zien. Een versie noemt hoogstens 32 pakketten en samen hoogstens 128 MiB aan goedgekeurde bestanden. Een pakket dat geen lijst goedkeurt, of een pakket dat twee keer genoemd wordt, is 422 op packages.<i>.

Een bibliotheek uit de image noemen mag, en zet hem vast: laat een latere image hem weg, dan draait de versie niet meer, in plaats van te falen bij de import.

Bij de eerste aanroep van een versie op een computer kopieert Core de goedgekeurde bestanden naar de sandbox en installeert ze daar; het script vindt ze op het gewone importpad (PYTHONPATH, en NODE_PATH voor require; een ES-module bereikt er een via createRequire). Mislukt de installatie, dan is het antwoord als bij een falend script, met de uitvoer van de installer, en draait de entrypoint niet.

Een pakket goedkeuren voor je organisatie

Een sleutel met management keurt per aanroep één bestand goed. De body is het bestand zelf; naam, versie en bestandsnaam staan in de query:

curl -s -X POST \
    "$CORE_URL/packages?ecosystem=pypi&name=qrcode&version=8.2&filename=qrcode-8.2-py3-none-any.whl" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/octet-stream" \
    --data-binary @qrcode-8.2-py3-none-any.whl
  • Upload voor PyPI de wheel (.whl), nooit een bronpakket: de sandbox heeft geen compiler en bouwt niets. De wheel moet op de sandbox laden: een wheel in puur Python (py3-none-any) doet dat altijd; een gecompileerde moet gebouwd zijn voor de Python en het platform van de image, CPython 3.12 op Linux x86-64 (manylinux, Runtimes). Een wheel die niet past, of waarvan de bestandsnaam niet de naam en versie draagt die je opgaf, is 422 op filename. Een script lokaal testen laat zien hoe je een wheel in de image probeert voordat je hem uploadt.
  • Upload voor npm de tarball die npm pack schrijft (.tgz). Die wordt geïnstalleerd zonder zijn installatiescripts te draaien, dus een pakket dat een bouwstap nodig heeft, zoals een native addon, werkt niet.
  • Een bestand is hoogstens 32 MiB. Core berekent en bewaart de SHA-256-digest; GET /packages/{package_id} geeft die.
  • De lijst van je organisatie heeft hoogstens 500 goedkeuringen; een goedkeuring daarboven is 409. Een naam en versie die er al op staat, is ook 409; wil je een andere versie gebruiken, keur die dan los goed.
  • Houdt een organisatie boven de jouwe het sleutelbeheer aan zichzelf, dan zijn goedkeuren en intrekken aan haar beheerders, en krijgt je eigen sleutel 403.

Een goedkeuring hoort alleen bij je eigen organisatie. De scripts van geen enkele andere organisatie kunnen hem noemen.

Een pakket intrekken

DELETE /packages/{package_id} trekt een goedkeuring van je organisatie in en verwijdert het bestand; het antwoord is 204. Een pakket dat de installatie goedkeurde, is 403: alleen je operator trekt die in.

Een versie wordt nooit herschreven, dus een versie die een ingetrokken pakket noemt, blijft het noemen, en haar volgende aanroep wordt geweigerd met This script needs a package that is no longer approved: …. Maak een nieuwe versie zonder het pakket, of met een goedgekeurde vervanger. Keur je precies hetzelfde bestand opnieuw goed, dan draaien die versies weer; een ander bestand onder dezelfde naam en versie niet, want elke versie legde de digest vast van het bestand waarmee ze getest is. Hetzelfde geldt als je operator een pakket van de installatie intrekt of overstapt op een image zonder een bibliotheek die een versie noemt.

Een script delen

Een script kan in een publicatie worden opgenomen, net als een prompt of een koppeling. De bestanden worden op digest naast de publicatie bewaard, pakketten die alleen jouw organisatie goedkeurde reizen met de bundel mee, en de abonnee heeft tooling en computer nodig. Verberg je de inhoud, dan toont de kopie van de abonnee de naam, de beschrijving en de parameters, maar niet de entrypoint en de bestanden, en draait ze in elke beurt op een eigen computer. Een gekoppelde kopie krijgt geen nieuwe versie en kan niet worden verwijderd (409); alleen een losgemaakte kan dat.

Verbruik en audit

  • De computer wordt in rekening gebracht zoals bij Computers: één record sandbox_seconds per computer. Pakketten installeren en het pakket wegschrijven horen bij de aanroep en tellen als computertijd.
  • Elke aanroep schrijft één verbruiksrecord tool_invocation met de naam script__<naam>. Heeft de prijslijst van je installatie een prijs voor die toolnaam, dan krijgt elke aanroep een prijs; zonder prijs kost een aanroep alleen zijn deel van de computer.
  • De audittrail legt script.created, script.version_created, script.updated (een versie-body die alleen labels of metadata wijzigde) en script.deleted vast; package.approved en package.revoked; en per aanroep computer.executed met soort script, het id van het script, de versie, de duur en de exitcode. Argumenten, uitvoer en bestandsnamen komen nooit in de audittrail.

Hetzelfde in de console staat op Scripts in de console.