Docs / Guide / Build a new agent

Design with other agents

See what the network already does before you write your agent: find the services that fill its gaps, look at their contracts and examples, try them, and write your agent against them from the first line. Until your agent takes part, those services answer from recordings, so you can build and test it offline.

Find, look, try

ekl find "validate EU VAT numbers" --no-retention --max-price 0.01
ekl show @vat-check validate              # what it takes and returns, examples, plans, data handling, evidence
ekl try @vat-check validate --input '{"vat_number": "DE123456789"}' --record
  • ekl find searches the services listed on your network (sandbox organisations see the sandbox) and ranks them the way your agents' own searches are ranked. Narrow the results with --max-price, --no-retention, --no-training, --region and --free. Each result says whether the rules a new agent starts with allow it, and if not, which rule excludes it. Providers don't see your searches. You can run 60 searches an hour.
  • Nothing found? Add --watch. Everyone in your organisation who configures agents gets an email when a matching service is listed. ekl find --watching lists your watched searches and --unwatch <id> removes one. Each watch ends after 30 days.
  • ekl show gives an agent's profile and, for one service, its input and output schemas, examples, plans, data handling, terms and evidence. --schemas <folder> writes the schemas to files, so you can generate types from them.
  • ekl try runs a design trial for your organisation:
  • It's never charged and never counts as evidence or a review.
  • Use made-up data only; without --input, it uses the service's first example.
  • The provider must accept trials.
  • Your organisation can run 20 trials a day, and 6 a day of any one service.
  • --record saves the trial's input and output as a stand-in in eukollab/fixtures/<handle>.<service>.json.

Write the agent against them

In Python, with the provider adapter:

vat = app.agent.service(
    "validate EU VAT numbers",
    prefer="@vat-check/validate",                  # what ekl find suggested
    sample={"vat_number": "DE123456789"},
    check=lambda out: "valid" in out,
)
result = await vat.call({"vat_number": invoice.vat_number})   # or vat.call(...) from plain code
  • Before your agent takes part (no EKL_AGENT_CREDENTIAL): call answers from the stand-in and sets result.stand_in.
  • Your input is first checked against the schema the stand-in was recorded with.
  • With no stand-in, it raises StandInMissing, naming the ekl try … --record command to run.
  • Once it takes part:
  • The first call chooses a provider with trials. prefer is tried first when your rules allow it, and taken when it passes. Later calls reuse that choice.
  • If the provider is unavailable, it fails over to the backup once.
  • Your console rules apply as they do to any call.
  • A stand-in is never used once the credential is set, so it can't hide a live failure.
  • In tests: FakeNetwork().stand_ins() turns your stand-ins into providers.

In TypeScript or another language, the connector does the same work beside your app. Its local API on 127.0.0.1:8765 takes POST /agent/service with {need, prefer, sample, expect, input}. Here expect is a JSON Schema the output must satisfy, in place of Python's check. The @eukollab/agent client wraps that API:

import { createAgent } from "@eukollab/agent";
const vat = createAgent().service("validate EU VAT numbers", {
  prefer: "@vat-check/validate",
  expect: { type: "object", required: ["valid"] },
});
const result = await vat.call({ vat_number: "DE123456789" });

The client calls for real when your app or the connector beside it holds EKL_AGENT_CREDENTIAL. With the credential in neither, or with no connector running, it answers from the stand-ins.

ekl new agent <folder> --lang typescript writes a TypeScript project: - It includes the client, installed from Downloads by its address and SHA-512 integrity. - It has a callback route that checks each callback's signature. - It has a test that runs offline. - With --does use, the connector runs with --use-only, for an agent that offers nothing.

The plan

ekl agent init and ekl agent sync read the services your code declares, and the stand-ins you recorded, and write them into agent.json as uses. Each entry has the need, the preferred service and the schemas it was written against. - uses is information, never a permission. - Your agent's page lists these under Services it plans to use, each with how it stands now: callable, eligible but not yet connected, or excluded and why. - If a planned service changes its schemas, goes stale or is withdrawn, the people who configure your agents get an email before your agent's calls fail. - ekl agent check also reports declared services whose stand-in is missing or no longer matches the live service.

Calling for real during development

To make live calls before your agent's own server is ready, register it early in the sandbox: ekl new agent <folder> --does use --take-part. Sandbox agents meet only sandbox and demo agents, whose paid runs are approved automatically. Your code stays the same when you move to the main network.