Werkzeuge
Ein Tool-Modul läuft auf jedem Agent-Harness. beeuni.yaml listet die Beeuni-Tools und die projektspezifischen Tools auf, und die tools-Liste jedes Agents legt fest, wer sie aufrufen darf.
Ein Tool ist eine Funktion, die das Modell während eines Turns aufruft. Eine Session hat drei Arten von Tools, auf beiden Harnesses, Standard-Harness und Experimental-Harness:
| Art | Namen | Implementiert von |
|---|---|---|
| Harness-Tools | bash, read, write, edit, glob, grep, task, question, … |
Dem Harness. |
| Beeuni-Tools | web_search, image_search, scrape_webpage, memory, show |
Beeuni. beeuni.yaml führt jedes als <name>: beeuni:<name> auf. Ein Projekt ohne Schlüssel tools: erhält alle fünf. |
| Projekt-Tools | Jeder von dir deklarierte Name | Deinem Projekt: ein Modul, deklariert unter tools: in beeuni.yaml. |
Beeuni-Tools und Projekt-Tools sind harness-unabhängig. Der Sandbox-Daemon lädt für jedes Tool ein Modul und führt es für beide Harnesses mit demselben Namen, denselben Argumenten und derselben Ausgabe aus. Experimental-Harness ruft das Modul im Prozess des Daemons auf. Standard-Harness ruft es über ein vom Daemon geschriebenes Plugin auf, das jeden Aufruf an den Daemon weiterleitet. Ein Modul importiert niemals ein Harness-Paket.
Beeuni-Tools in beeuni.yaml
Ein neues Projekt führt die fünf Beeuni-Tools unter tools: auf:
tools:
web_search: beeuni:web_search # maintained by Beeuni, updated automatically
image_search: beeuni:image_search
scrape_webpage: beeuni:scrape_webpage
memory: beeuni:memory
show: beeuni:show
# lookup_order: tools/lookup_order.ts # your own tool: a module in your repo
beeuni:<name> bedeutet: das von Beeuni gepflegte Tool. Eine Korrektur daran erreicht jedes
Projekt, das es aufführt, ohne dass das Projekt geändert werden muss.
Welche Beeuni-Tools eine Session erhält
beeuni.yaml |
Die Session erhält |
|---|---|
Kein Schlüssel tools:, weder in der Stammdatei noch in einer importierten Datei |
Alle fünf Beeuni-Tools. Ein Projekt, das vor Einführung dieser Liste erstellt wurde, behält sie alle. |
Einen Schlüssel tools:, auch einen leeren (tools: {} oder tools:, wenn alle Zeilen gelöscht wurden) |
Nur die Beeuni-Tools, die darin als beeuni:<name> oder als Modul aufgeführt sind, das das Tool ersetzt. |
Die projektspezifischen Tools werden in beiden Fällen geladen.
Anzeigen, welche Tools eine Session erhält
beeuni tools ls liest beeuni.yaml und seine Importe und gibt jedes Tool aus, das eine
Session erhält, gefolgt von den Beeuni-Tools, die das Projekt entfernt hat:
$ beeuni tools ls
NAME KIND SOURCE
web_search beeuni (overridden) tools/web_search.ts
scrape_webpage beeuni beeuni:scrape_webpage
memory beeuni beeuni:memory
show beeuni beeuni:show
lookup_order project tools/lookup_order.ts
Removed Beeuni tools: image_search
Add `<name>: beeuni:<name>` under `tools:` to get one back.
| Art | Bedeutung |
|---|---|
beeuni |
Ein Beeuni-Tool, aufgeführt als beeuni:<name> (oder alle, wenn kein Schlüssel tools: vorhanden ist). |
beeuni (overridden) |
Ein Beeuni-Toolname mit Modulpfad: Stattdessen wird das Modul des Projekts ausgeführt. |
project |
Ein projektspezifisches Tool. |
beeuni tools ls --json gibt { manifest, tools_key, tools: [{ name, kind, source }], removed } aus.
Ein Beeuni-Tool entfernen
Lösche seine Zeile unter tools:. Jeder Agent des Projekts verliert das Tool,
auf beiden Harnesses und in jeder Session, die nach dem Mergen des Änderungsauftrags startet.
Wenn du ein Tool nur für einen Agent entfernen willst, verwende stattdessen
agents.<name>.tools.
In einer Session eines Projekts, das ein Tool entfernt hat:
- Standard-Harness bietet dem Modell das Tool nicht an.
- Experimental-Harness bietet das Tool nicht an. Ein Aufruf schlägt mit
Tool show not foundfehl (fürshow). - Der Daemon antwortet auf
POST /beeuni/tools/<name>mit404undno tool named <name> is loaded. - Ein Skill, der das Tool nennt, wird weiterhin geladen. Zum Beispiel nennt
beeuni-memorymemory. Das Modell liest den Skill, findet kein solches Tool und verwendet andere Tools: Ohnememoryliest und bearbeitet es mit den Datei-Tools die Dateien untermemory/.
Ein Beeuni-Tool ändern: auskoppeln
beeuni tools eject <name> erstellt eine eigene Kopie eines Beeuni-Tools im Projekt:
$ beeuni tools eject web_search
✓ Ejected web_search
wrote tools/web_search.ts (the Beeuni source, now the project's to change)
set beeuni.yaml: tools.web_search: tools/web_search.ts
Next:
1. Edit tools/web_search.ts. Keep the default export: { description, parameters, execute(args, context) }.
2. beeuni validate
3. git add tools/web_search.ts beeuni.yaml && git commit -m "Own the web_search tool"
4. Open a change request: git push origin HEAD && beeuni cr open --title "Own the web_search tool"
Sessions load the copy after the change request merges.
- Es schreibt den Beeuni-Quellcode – dieselben Bytes, die die Sandbox ausführt – nach
tools/<name>.ts. Die Datei importiert nurnode:*-Module und liestBEEUNI_API_URL,BEEUNI_TOKENsowie Provider-Schlüssel auscontext.env, sodass sie direkt ausführbar ist. - Es setzt
<name>: tools/<name>.tsinbeeuni.yaml, und zwar in der Datei, die den Eintrag deklariert (der Stammdatei oder einer importierten Datei). Alle anderen Zeilen und Kommentare bleiben erhalten. Die geänderte Zeile endet mit# ejected from beeuni:<name>. - Wenn kein Schlüssel
tools:vorhanden ist, wird einer erstellt und die übrigen vier Beeuni-Tools werden alsbeeuni:<name>aufgeführt, sodass durch das Auskoppeln nichts entfernt wird. - Der Vorgang wird abgebrochen, wenn
tools/<name>.tsvorhanden ist oder das Tool bereits auf ein anderes Modul verweist.--forceüberschreibt. - Ein Name, der kein Beeuni-Tool ist, wird abgelehnt.
Die Kopie gehört dir. Beeuni aktualisiert sie nicht mehr. Um zum gepflegten Tool zurückzukehren,
setze die Zeile wieder auf <name>: beeuni:<name> und lösche die Datei.
Ohne Auskoppeln überschreiben
Ein Beeuni-Toolname mit Modulpfad ersetzt das Beeuni-Tool auf jedem Harness:
tools:
web_search: integrations/search/web_search.ts
Ansichten der Web-UI
Die Web-UI hat für jedes Beeuni-Tool eine Ansicht, die anhand des Toolnamens ausgewählt wird. Die
Ansichten show und memory lesen die Argumente des Aufrufs (type, path, url,
content, items; command, path). Die Ansichten web_search, image_search und
scrape_webpage lesen das Ausgabe-JSON. Eine geänderte Kopie mit demselben
Namen muss diese Argumente und diese Ausgabeform beibehalten, sonst zeigt die UI die unverarbeitete
Ausgabe.
Validierung
beeuni validate prüft die Liste:
<name>inbeeuni:<name>muss ein Beeuni-Tool sein, und der Schlüssel muss mit ihm übereinstimmen.web_search: beeuni:image_searchist ein Fehler:must be `beeuni:web_search` (the Beeuni tool) or a repo-relative path to a .ts or .js module (e.g. `tools/web_search.ts`) that replaces it.- Ein Schlüssel
tools:, der kein Beeuni-Tool aufführt, löst eine Warnung aus:Sessions of this project get no Beeuni tool (web_search, image_search, scrape_webpage, memory, show). Add `<name>: beeuni:<name>` to keep one.Sie weist auf ein Projekt hin, das sein erstes eigenes Tool hinzugefügt und versehentlich die fünf Beeuni-Tools entfernt hat. - Wenn
toolseines Agents ein Beeuni-Tool nennt, das das Projekt nicht lädt, wird eine Warnung ausgegeben:"show" is a Beeuni tool this project does not load: add `show: beeuni:show` under the top-level `tools`, or remove it here.
Die Manifest-Referenz enthält alle Regeln.
Ein Projekt-Tool schreiben
// tools/lookup_order.ts
export default {
description: 'Look up an order by id. Returns its status and carrier.',
parameters: {
type: 'object',
properties: {
id: { type: 'string', description: 'The order id, e.g. "A-1042"' },
include_items: { type: 'boolean', description: 'Also list the items' },
},
required: ['id'],
},
async execute(args, context) {
const response = await fetch(`https://orders.example.com/v1/orders/${args.id}`, {
headers: { authorization: `Bearer ${context.env.ORDERS_API_KEY}` },
signal: context.signal,
})
if (!response.ok) throw new Error(`orders API answered ${response.status}`)
return await response.json()
},
}
# beeuni.yaml
tools:
web_search: beeuni:web_search
# … the other Beeuni tools you keep
lookup_order: tools/lookup_order.ts
Der Standardexport ist ein einfaches Objekt:
| Feld | Regel |
|---|---|
description |
Nichtleere Zeichenfolge. Das Modell liest sie, um zu entscheiden, wann das Tool aufgerufen werden soll. |
parameters |
JSON Schema der Argumente, type: 'object'. Das Modell erhält es unverändert; führe erforderliche Argumente also unter required auf. Beeuni validiert die Argumente nicht dagegen. |
execute(args, context) |
Gibt eine Zeichenfolge oder einen beliebigen JSON-Wert zurück (als eingerücktes JSON gesendet). Darf async sein. Ein ausgelöster Fehler ist der Fehler des Tools; das Modell liest seine Meldung. |
context enthält:
| Feld | Beschreibung |
|---|---|
sessionId |
Die Beeuni-Session, zu der der Aufruf gehört. |
agent |
Der Agent, der den Aufruf getätigt hat. |
directory |
Der Checkout des Projekts, /workspace. Löse relative Pfade relativ dazu auf. |
env |
Die Umgebung der Box sowie die Geheimnisse, die dieser Agent aktuell erhält. Ein Geheimnis liest du mit context.env.NAME: Ein Geheimnis, das nach dem Start der Box geändert wurde, ist in context.env enthalten, nicht in process.env. |
signal |
Ein AbortSignal, das abgebrochen wird, wenn der Nutzer den Turn beendet. Übergib es an fetch. |
- Ausgabegröße. Eine Ausgabe mit mehr als 50 KB oder 2.000 Zeilen wird vollständig in einer Datei im temporären Verzeichnis der Sandbox gespeichert. Das Modell erhält den Anfang, die Größe und den Dateipfad. Gib zurück, was das Modell benötigt, keinen unbearbeiteten Dump.
- Fehler. Ein ausgelöster Fehler beendet den Aufruf, und das Modell liest die Fehlermeldung. Formuliere eine Meldung, aus der hervorgeht, was geändert werden muss.
- Importe. Ein Modul darf
node:*-Module, Bun-APIs und relative Dateien importieren. Ein Paket wird aus einemnode_modulesneben oder oberhalb des Moduls aufgelöst. Die Sandbox installiert keine Pakete für ein Tool, und ein Config-Release enthält nur Dateien, die Git verfolgt. Verwendefetchfür HTTP-APIs. TypeScript wird ohne Build-Schritt ausgeführt. - Fehler beim Laden. Ein Modul, das nicht geladen werden kann (fehlende Datei, kein Standardexport, ein
parameters, das kein Objektschema ist, ein Fehler beim Import oder ein nicht auflösbares Paket), wird ausgelassen; die übrigen Tools werden weiterhin geladen. Der Daemon protokolliert[tools] project tools that did not loadmit dem Grund für jedes Tool.
parameters mit zod
zod 4 erzeugt dasselbe JSON Schema:
import { z } from 'zod'
export default {
description: 'Look up an order by id.',
parameters: z.toJSONSchema(z.object({ id: z.string().describe('The order id') })),
async execute(args) {
return `order ${args.id}: shipped`
},
}
Dieses Modul wird nur geladen, wenn zod aus einem node_modules im Checkout aufgelöst werden kann, in dem die Session läuft. Andernfalls schlägt es mit Cannot find package 'zod' fehl.
Um das Schema mit zod zu schreiben und als einfaches JSON Schema bereitzustellen, gib es einmal aus und kopiere die Ausgabe nach parameters:
bun -e "import { z } from 'zod'; console.log(JSON.stringify(z.toJSONSchema(z.object({ id: z.string() })), null, 2))"
Beispiel: Eine HTTP-API mit einem Projektgeheimnis aufrufen
Speichere den Schlüssel als Projektgeheimnis. Der Befehl liest den Wert von stdin:
beeuni secrets set WEATHER_API_KEY=-
Gewähre den Agents, die das Tool aufrufen, Zugriff auf das Geheimnis. Der beeuni-Agent des Startprojekts hat secrets: all. Ein Agent mit eingeschränktem Umfang führt es auf: secrets: [WEATHER_API_KEY].
Schreibe das Modul:
// tools/weather_now.ts
export default {
description: 'Current weather for a city: temperature in °C and conditions.',
parameters: {
type: 'object',
properties: { city: { type: 'string', description: 'City name, e.g. "Berlin"' } },
required: ['city'],
},
async execute(args, context) {
const key = context.env.WEATHER_API_KEY
if (!key) throw new Error('WEATHER_API_KEY is not set: run `beeuni secrets set WEATHER_API_KEY=-` and grant it to this agent.')
const url = `https://api.weather.example.com/v1/current?city=${encodeURIComponent(args.city)}`
const response = await fetch(url, { headers: { authorization: `Bearer ${key}` }, signal: context.signal })
if (!response.ok) throw new Error(`weather API answered ${response.status}: ${await response.text()}`)
const data = await response.json()
return { city: args.city, temperature_c: data.temp_c, conditions: data.conditions }
},
}
Deklariere es:
tools:
# … the Beeuni tools you keep
weather_now: tools/weather_now.ts
Beispiel: web_search überschreiben
beeuni tools eject web_search schreibt tools/web_search.ts und setzt
web_search: tools/web_search.ts. Ändere anschließend die Kopie. Um beispielsweise nur Ergebnisse von einer Website zu erhalten, füge die Website vor der Anfrage jeder Abfrage in execute hinzu:
// tools/web_search.ts, inside execute()
const queries = String(args.query ?? '').split('|||').map((query) => query.trim()).filter(Boolean)
.map((query) => `site:docs.example.com ${query}`)
Behalte den Namen, die Argumente und das Ausgabe-JSON bei, damit Skills, die web_search nennen, und die Ansicht der Web-UI weiterhin funktionieren.
Ein Tool testen
beeuni validate prüft den Namen, den Pfad, eine fehlende Datei und die Werte von
beeuni:. beeuni tools ls zeigt, welche Tools eine Session erhält.
Führe anschließend einen Commit und Push durch und öffne einen Änderungsauftrag. Starte nach dem Mergen eine Session und fordere einen Aufruf mit echten Argumenten an:
beeuni sessions new --wait --prompt "Call the weather_now tool once with city Berlin and print its output."
Ein Tool, das nicht geladen wird, wird dem Modell nicht angeboten. Ein Tool, das einen Fehler auslöst,
antwortet mit seiner Fehlermeldung. beeuni sessions log <id> gibt die Nachrichten der Session aus, einschließlich jedes Tool-Aufrufs und seines Status.
Tools deklarieren
tools: ordnet jeden Toolnamen seinem Modul zu oder einen Beeuni-Toolnamen beeuni:<name>. Du kannst den Ordner eines Moduls frei wählen.
tools:
web_search: beeuni:web_search
memory: beeuni:memory
lookup_order: tools/lookup_order.ts
crm_note: integrations/crm/note.ts
- Ein Name muss in snake_case und höchstens 64 Zeichen lang sein:
^[a-z][a-z0-9_]{0,63}$. - Ein Harness-Toolname ist ein Fehler. Ein Beeuni-Toolname akzeptiert
beeuni:<name>oder einen Modulpfad; das Modul ersetzt das Beeuni-Tool auf jedem Harness. - Ein Pfad muss relativ zum Repository sein und mit
.ts,.js,.mts,.mjs,.ctsoder.cjsenden. - Eine unter
imports:aufgeführte Datei darf Tools deklarieren. Wird ein Name in zwei Dateien deklariert, ist das ein Fehler. Ein Schlüsseltools:in einer importierten Datei zählt für die Auswahlregel als Schlüsseltools:.
Die Manifest-Referenz enthält alle Regeln.
Wer welches Tool verwenden darf
agents.<name>.tools legt fest, welche Tools das Modell eines Agents sieht. Sie führt Harness-, Beeuni- und Projekt-Tools gleichermaßen auf.
agents:
beeuni:
tools: all # every tool (the default)
researcher:
tools: [read, grep, web_search, lookup_order] # only these
support:
tools:
exclude: [bash, write, edit] # every tool but these
greeter:
tools: none # no tool
| Wert | Der Agent erhält |
|---|---|
weggelassen oder all |
Alle Tools. |
none |
Kein Tool. |
| eine Liste | Nur die aufgeführten Tools. Eine Liste mit * ist all. |
{ exclude: [...] } |
Alle Tools außer den aufgeführten. |
{ bash: false, … } |
Die frühere Map-Form: false entfernt ein Tool. |
toolsbestimmt die Sichtbarkeit. Die Regeln fürpermissiondes Agents entscheiden weiterhin, ob ein Aufruf erlaubt, nachzufragen oder abzulehnen ist. Ein Tool, das nicht in der Liste steht, wird dem Modell verborgen und bei einem Aufruf abgelehnt.- Eine Agent-Liste kann kein Beeuni-Tool hinzufügen, das das Projekt nicht lädt. Führe es zuerst unter
tools:auf oberster Ebene auf. - Ein mit dem Tool
taskgestarteter Subagent erhält auf Experimental-Harness nur die Tools, die sowohl seine eigene Liste als auch die Liste des Session-Agents zulassen. Auf Standard-Harness erhält er die Tools aus seiner eigenen Liste: Standard-Harness wendet die Regeln eines Agents nur auf diesen Agent an. Damit ein Agent keine Delegation ausführen kann, lasstaskaus seiner Liste weg. - Connector-Tools folgen
agents.<name>.connectors, nicht dieser Liste. beeuni validatewarnt vor einem Namen, der weder ein Harness-, Beeuni- noch ein Projekt-Tool ist, und vor einem Beeuni-Tool, das das Projekt nicht lädt. Ein Tippfehler in einerexclude-Liste lässt das echte Tool aktiviert.
In Standard-Harness umfasst bash auch die Tools pty_* des Terminal-Plugins. Außerdem verwenden write, edit und apply_patch dieselbe Berechtigung: Wenn eines aufgeführt wird, werden alle drei angezeigt; wenn eines ausgeschlossen wird, werden alle drei verborgen. Experimental-Harness hat separate Tools write und edit.
Wann eine Änderung wirksam wird
Eine Session lädt ihre Tools beim Start ihrer Laufzeitumgebung. Eine Änderung wird nach dem Mergen des Änderungsauftrags wirksam: Neue Sessions laden sie; bei Config-Releases lädt eine laufende Session sie bei der nächsten Konvergenz. Auf Experimental-Harness startet eine Änderung an einem Projekt-Tool oder an der Liste der Beeuni-Tools die Laufzeitumgebung direkt neu, sofern gerade kein Turn läuft; das Gespräch wird fortgesetzt.
Tools in harnesses/opencode/tools/
Standard-Harness lädt weiterhin benutzerdefinierte Tools aus seinem Konfigurationsverzeichnis. Experimental-Harness tut das nicht.
Projekte, die vor den gehosteten Tools erstellt wurden, enthalten dort Kopien der Beeuni-Tools
(web_search.ts, memory.ts, …).
- In Standard-Harness hat ein Tool in diesem Ordner Vorrang vor dem gehosteten Tool mit demselben Namen. Daher behält ein Projekt seine Kopie, bis es sie löscht. Lösche die Kopien der Beeuni-Tools: Der Daemon stellt die Tools bereit, die
beeuni.yamlaufführt, auf beiden Harnesses. - Damit ein Standard-Harness-Tool auf beiden Harnesses ausgeführt wird, verschiebe es aus dem Ordner, ersetze
tool({ description, args, execute })durch ein einfaches Objekt, dessenparametersJSON Schema ist, lies Geheimnisse auscontext.envund deklariere es untertools:.