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¶
- De capability
tooling, om scripts te registreren en aan te bieden. - De capability
computer, om ze te draaien. Je organisatie moetcomputertoestaan. filesals het model met de bijlagen van een beurt moet werken of als je bestanden via een upload registreert, enartifactsals 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 metPOST /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 heeftfilesnodig 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_presentatiemet{"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¶
- Eerst worden de argumenten gecontroleerd. Argumenten die niet aan
parametersvoldoen, krijgenTool 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. - 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.
- De entrypoint draait onder één time-out: de kortste van
timeout_secondsvan de versie,computer.exec_timeout_secondsvan je sleutel en de limiet van de installatie. Het model kan die niet verlengen. -
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 -
Elk bestand dat direct in
ARTIFIC_OUTPUTSstaat, 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 zonderartifactsstaat erbij alsleft 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, is422opfilename. 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 packschrijft (.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 ook409; 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_secondsper computer. Pakketten installeren en het pakket wegschrijven horen bij de aanroep en tellen als computertijd. - Elke aanroep schrijft één verbruiksrecord
tool_invocationmet de naamscript__<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) enscript.deletedvast;package.approvedenpackage.revoked; en per aanroepcomputer.executedmet soortscript, 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.