Outils
Un module d’outils fonctionne sur chaque harnais d’agent. beeuni.yaml répertorie les outils Beeuni et ceux propres au projet, et la liste d’outils de chaque agent détermine qui peut les appeler.
Un outil est une fonction que le modèle appelle pendant un tour. Une session comporte trois types d’outils, dans les deux environnements, harness standard et harness expérimental :
| Type | Noms | Implémenté par |
|---|---|---|
| Outils de l’environnement | bash, read, write, edit, glob, grep, task, question, … |
L’environnement. |
| Outils Beeuni | web_search, image_search, scrape_webpage, memory, show |
Beeuni. beeuni.yaml répertorie chacun sous la forme <name>: beeuni:<name>. Un projet sans clé tools: obtient les cinq. |
| Outils du projet | Tout nom que vous déclarez | Votre projet : un module déclaré sous tools: dans beeuni.yaml. |
Les outils Beeuni et ceux du projet sont indépendants de l’environnement. Le démon du bac à sable charge un module par outil et l’exécute dans l’un ou l’autre environnement, avec le même nom, les mêmes arguments et la même sortie. harness expérimental appelle le module dans le processus du démon. harness standard l’appelle au moyen d’un plug-in écrit par le démon, qui transmet chaque appel au démon. Un module n’importe jamais de paquet d’environnement.
Outils Beeuni dans beeuni.yaml
Un nouveau projet répertorie les cinq outils Beeuni sous tools: :
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> signifie qu’il s’agit de l’outil maintenu par Beeuni. Un correctif le concernant est appliqué à chaque projet qui le répertorie, sans modification du projet.
Outils Beeuni disponibles dans une session
beeuni.yaml |
Outils disponibles dans la session |
|---|---|
Aucune clé tools:, ni dans le fichier racine ni dans un fichier importé |
Les cinq outils Beeuni. Un projet créé avant l’existence de cette liste les conserve tous. |
Une clé tools:, même vide (tools: {} ou tools: dont toutes les lignes ont été supprimées) |
Uniquement les outils Beeuni qu’elle répertorie, sous forme de beeuni:<name> ou de module remplaçant l’outil. |
Dans les deux cas, les outils propres au projet sont chargés.
Voir les outils disponibles dans une session
beeuni tools ls lit beeuni.yaml et ses imports, puis affiche chaque outil disponible dans une session, suivi des outils Beeuni supprimés par le projet :
$ 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.
| Type | Signification |
|---|---|
beeuni |
Un outil Beeuni répertorié sous la forme beeuni:<name> (ou tous les outils, en l’absence de clé tools:). |
beeuni (overridden) |
Un nom d’outil Beeuni accompagné d’un chemin de module : le module du projet est exécuté à la place. |
project |
Un outil propre au projet. |
beeuni tools ls --json affiche { manifest, tools_key, tools: [{ name, kind, source }], removed }.
Supprimer un outil Beeuni
Supprimez sa ligne sous tools:. Tous les agents du projet perdent l’outil, dans les deux environnements, pour chaque session démarrée après la fusion de la demande de modification. Pour supprimer un outil pour un seul agent, utilisez plutôt agents.<name>.tools.
Dans une session d’un projet qui a supprimé un outil :
- harness standard ne propose pas l’outil au modèle.
- harness expérimental ne propose pas l’outil. Un appel à celui-ci échoue avec
Tool show not found(pourshow). - Le démon répond à
POST /beeuni/tools/<name>avec404etno tool named <name> is loaded. - Une compétence qui nomme l’outil continue de se charger. Par exemple,
beeuni-memorynommememory. Le modèle lit la compétence, constate que l’outil n’existe pas et utilise d’autres outils : sansmemory, il lit et modifie les fichiers sousmemory/avec les outils de gestion des fichiers.
Modifier un outil Beeuni : l’extraire
beeuni tools eject <name> fournit au projet sa propre copie d’un outil Beeuni :
$ 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.
- Il écrit le code source Beeuni, c’est-à-dire les mêmes octets que ceux exécutés par le bac à sable, dans
tools/<name>.ts. Le fichier importe uniquement des modulesnode:*et litBEEUNI_API_URL,BEEUNI_TOKENet les clés des fournisseurs depuiscontext.env; il est donc exécutable tel quel. - Il définit
<name>: tools/<name>.tsdansbeeuni.yaml, dans le fichier qui déclare le point d’entrée (le fichier racine ou un fichier importé). Toutes les autres lignes et tous les commentaires sont conservés. La ligne modifiée se termine par# ejected from beeuni:<name>. - En l’absence de clé
tools:, il en crée une et répertorie les quatre autres outils Beeuni sous la formebeeuni:<name>, de sorte que l’extraction ne supprime rien. - Il refuse de continuer si
tools/<name>.tsexiste ou si l’outil pointe déjà vers un autre module.--forceécrase le fichier. - Il refuse tout nom qui ne correspond pas à un outil Beeuni.
La copie vous appartient. Beeuni ne la met plus à jour. Pour revenir à l’outil maintenu, remplacez la ligne par <name>: beeuni:<name> et supprimez le fichier.
Remplacer un outil sans l’extraire
Un nom d’outil Beeuni accompagné d’un chemin de module remplace l’outil Beeuni dans tous les environnements :
tools:
web_search: integrations/search/web_search.ts
Vues de l’interface Web
L’interface Web comporte une vue pour chaque outil Beeuni, sélectionnée par son nom. Les vues show et memory lisent les arguments de l’appel (type, path, url, content, items ; command, path). Les vues web_search, image_search et scrape_webpage lisent le JSON de sortie. Une copie modifiée qui conserve le nom doit conserver ces arguments et cette structure de sortie, sinon l’interface affiche la sortie brute.
Validation
beeuni validate vérifie la liste :
<name>dansbeeuni:<name>doit être un outil Beeuni et la clé doit lui correspondre.web_search: beeuni:image_searchest une erreur :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.- Une clé
tools:qui ne répertorie aucun outil Beeuni déclenche un avertissement :Sessions of this project get no Beeuni tool (web_search, image_search, scrape_webpage, memory, show). Add `<name>: beeuni:<name>` to keep one.Cela permet de repérer un projet qui ajoute son premier outil et supprime accidentellement les cinq autres. - Un agent dont
toolsnomme un outil Beeuni que le projet ne charge pas déclenche un avertissement :"show" is a Beeuni tool this project does not load: add `show: beeuni:show` under the top-level `tools`, or remove it here.
La référence du manifeste contient toutes les règles.
Écrire un outil de projet
// 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
L’export par défaut est un objet simple :
| Champ | Règle |
|---|---|
description |
Chaîne non vide. Le modèle la lit pour décider quand appeler l’outil. |
parameters |
Schéma JSON des arguments, type: 'object'. Le modèle le reçoit tel quel ; indiquez donc les arguments obligatoires dans required. Beeuni ne valide pas les arguments par rapport à ce schéma. |
execute(args, context) |
Renvoie une chaîne ou une valeur JSON quelconque (transmise sous forme de JSON indenté). Peut être async. Toute erreur levée est l’erreur de l’outil, et le modèle en lit le message. |
context contient :
| Champ | Description |
|---|---|
sessionId |
La session Beeuni à laquelle l’appel appartient. |
agent |
L’agent qui a effectué l’appel. |
directory |
La copie de travail du projet, /workspace. Résolvez les chemins relatifs par rapport à celle-ci. |
env |
L’environnement du conteneur, ainsi que les secrets reçus par cet agent, dans leur état actuel. Lisez un secret avec context.env.NAME : un secret modifié après le démarrage du conteneur se trouve dans context.env, et non dans process.env. |
signal |
Un AbortSignal qui annule l’opération si l’utilisateur arrête le tour. Transmettez-le à fetch. |
- Taille de la sortie. Toute sortie dépassant 50 Ko ou 2 000 lignes est enregistrée intégralement dans un fichier du répertoire temporaire du bac à sable. Le modèle reçoit le début du contenu, la taille et le chemin du fichier. Renvoyez ce dont le modèle a besoin, pas un vidage brut.
- Erreurs. Une erreur levée met fin à l’appel, et le modèle lit son message. Le message d’erreur doit indiquer la modification à apporter.
- Imports. Un module peut importer des modules
node:*, des API Bun et des fichiers relatifs. Un paquet est résolu depuis unnode_modulessitué à côté du module ou dans un répertoire parent. Le bac à sable n’installe aucun paquet pour un outil, et une version de configuration ne contient que les fichiers suivis par Git. Utilisezfetchpour les API HTTP. TypeScript s’exécute sans étape de compilation. - Échecs. Un module qui ne se charge pas (fichier manquant, absence d’export par défaut,
parametersqui n’est pas un schéma d’objet, erreur à l’importation ou paquet introuvable) est ignoré, et les autres outils continuent de se charger. Le démon journalise[tools] project tools that did not loadavec la raison, pour chaque outil.
parameters avec zod
zod 4 génère le même schéma JSON :
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`
},
}
Ce module ne se charge que si zod peut être résolu depuis un node_modules dans la copie de travail où s’exécute la session. Sinon, il échoue avec Cannot find package 'zod'.
Pour écrire le schéma avec zod et fournir un schéma JSON brut, affichez-le une fois et collez le résultat dans parameters :
bun -e "import { z } from 'zod'; console.log(JSON.stringify(z.toJSONSchema(z.object({ id: z.string() })), null, 2))"
Exemple : appeler une API HTTP avec un secret du projet
Enregistrez la clé comme secret du projet. La commande lit sa valeur depuis l’entrée standard :
beeuni secrets set WEATHER_API_KEY=-
Accordez le secret aux agents qui appellent l’outil. L’agent beeuni du modèle de départ dispose de secrets: all. Un agent avec des permissions limitées doit le répertorier : secrets: [WEATHER_API_KEY].
Écrivez le module :
// 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 }
},
}
Déclarez-le :
tools:
# … the Beeuni tools you keep
weather_now: tools/weather_now.ts
Exemple : remplacer web_search
beeuni tools eject web_search écrit tools/web_search.ts et définit web_search: tools/web_search.ts. Modifiez ensuite la copie. Par exemple, pour ne conserver les résultats que d’un seul site, ajoutez le site à chaque requête dans execute, avant la requête :
// 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}`)
Conservez le nom, les arguments et le JSON de sortie pour que les compétences qui nomment web_search et la vue de l’interface Web continuent de fonctionner.
Tester un outil
beeuni validate vérifie le nom, le chemin, l’absence d’un fichier et les valeurs beeuni:. beeuni tools ls affiche les outils disponibles dans une session.
Validez ensuite les modifications, envoyez-les et ouvrez une demande de modification. Après sa fusion, démarrez une session et demandez un appel avec des arguments réels :
beeuni sessions new --wait --prompt "Call the weather_now tool once with city Berlin and print its output."
Un outil qui ne se charge pas n’est pas proposé au modèle. Un outil qui lève une erreur répond en affichant son message d’erreur. beeuni sessions log <id> affiche les messages de la session, avec chaque appel d’outil et son état.
Déclarer des outils
tools: associe chaque nom d’outil à son module, ou un nom d’outil Beeuni à beeuni:<name>. Vous pouvez choisir librement le dossier du module.
tools:
web_search: beeuni:web_search
memory: beeuni:memory
lookup_order: tools/lookup_order.ts
crm_note: integrations/crm/note.ts
- Un nom doit être en snake_case et ne pas dépasser 64 caractères :
^[a-z][a-z0-9_]{0,63}$. - Un nom d’outil de l’environnement est une erreur. Un nom d’outil Beeuni accepte
beeuni:<name>ou un chemin de module ; le module remplace l’outil Beeuni dans tous les environnements. - Un chemin est relatif au dépôt et se termine par
.ts,.js,.mts,.mjs,.ctsou.cjs. - Un fichier répertorié sous
imports:peut déclarer des outils. Déclarer un nom dans deux fichiers est une erreur. Une clétools:dans un fichier importé compte comme une clétools:pour la règle de sélection.
La référence du manifeste contient toutes les règles.
Qui peut utiliser quels outils
agents.<name>.tools détermine les outils visibles par le modèle d’un agent. Cette liste englobe les outils de l’environnement, de Beeuni et du projet.
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
| Valeur | Outils disponibles pour l’agent |
|---|---|
omise ou all |
Tous les outils. |
none |
Aucun outil. |
| une liste | Uniquement les outils répertoriés. Une liste contenant * est all. |
{ exclude: [...] } |
Tous les outils, sauf ceux répertoriés. |
{ bash: false, … } |
L’ancien format de mappage : false supprime un outil. |
toolsdétermine la visibilité. Les règlespermissionde l’agent déterminent toujours si un appel est autorisé, soumis à confirmation ou refusé. Un outil qui ne figure pas dans la liste est masqué pour le modèle et tout appel à cet outil est refusé.- La liste d’un agent ne peut pas ajouter un outil Beeuni que le projet ne charge pas. Répertoriez-le d’abord sous
tools:, à la racine. - Un sous-agent lancé avec l’outil
taskreçoit uniquement, dans harness expérimental, les outils autorisés à la fois par sa propre liste et par celle de l’agent de session. Dans harness standard, il reçoit les outils de sa propre liste : harness standard applique les règles d’un agent à cet agent uniquement. Pour empêcher un agent de déléguer, ne mettez pastaskdans sa liste. - Les outils de connecteur suivent
agents.<name>.connectors, et non cette liste. beeuni validatesignale tout nom qui ne correspond pas à un outil de l’environnement, de Beeuni ou du projet, ainsi que tout outil Beeuni que le projet ne charge pas. Une faute de frappe dans une listeexcludelaisse l’outil réel activé.
Dans harness standard, bash s’applique également aux outils pty_* du plug-in de terminal, et write, edit et apply_patch partagent une même autorisation : en répertorier un affiche les trois, et en exclure un masque les trois. harness expérimental possède des outils write et edit distincts.
Prise d’effet des modifications
Une session charge ses outils au démarrage de son environnement d’exécution. Une modification prend effet après la fusion de la demande de modification : les nouvelles sessions la chargent et, avec les versions de configuration, une session en cours la charge lors de la prochaine convergence. Dans harness expérimental, une modification d’un outil du projet ou de la liste des outils Beeuni redémarre l’environnement d’exécution sur place quand aucun tour n’est en cours ; la conversation se poursuit.
Outils dans harnesses/opencode/tools/
harness standard continue de charger les outils personnalisés depuis son répertoire de configuration. harness expérimental ne le fait pas. Les projets créés avant la prise en charge des outils hébergés contiennent des copies des outils Beeuni à cet emplacement (web_search.ts, memory.ts, …).
- Dans harness standard, un outil de ce dossier remplace l’outil hébergé du même nom. Le projet conserve donc sa copie jusqu’à sa suppression. Supprimez les copies des outils Beeuni : le démon héberge ceux répertoriés dans
beeuni.yaml, dans les deux environnements. - Pour exécuter un outil harness standard dans les deux environnements, déplacez-le hors du dossier, remplacez
tool({ description, args, execute })par un objet simple dontparametersest un schéma JSON, lisez les secrets depuiscontext.envet déclarez-le soustools:.