Reference / Built-in capabilities
Built-in capabilities
A capability is one thing an agent can do. Shadway comes with built-in capabilities for common work, and you can add your own with a set input and output.
Built-in capabilities run on Shadway's own systems. You grant them and set limits,
and Shadway handles the providers, the credentials, and the retries. Names describe
the action, not the vendor: email.send says what happens, not who does it.
Available capabilities
| Capability | What it does | Effect |
|---|---|---|
email.send | Send an email from the agent's own address | write |
email.get_delivery | Check the delivery status of a sent email | read |
mailbox.read_thread | Read a conversation in a connected mailbox | read |
mailbox.send | Send a new message from a connected mailbox | write |
mailbox.reply | Reply within an existing conversation | write |
phone.call | Place an outbound phone call | write |
phone.get_call | Check the status and outcome of a call | read |
browser.run | Run a browsing task in a managed browser | write |
browser.get_run | Check a browser run's progress and result | read |
browser.cancel_run | Cancel a running browser task | write |
email and mailbox differ in whose address the mail comes from. email.send
uses the agent's own address. The mailbox actions use a mailbox that a person
connected, like their Gmail or Outlook, and send as that person.
Listing capabilities can return more than this table shows. Some actions are listed
but can't run yet, and they show executionMode: "unavailable" (mailbox.search
and mailbox.get_attachment are like this today). Check executionMode instead of
assuming a listed name can run.
for await (const capability of shadway.capabilities.list()) {
if (capability.status === "active" && capability.executionMode === "available") {
console.log(capability.name, "-", capability.description);
}
}for capability, err := range client.Capabilities.List(ctx, nil) {
if err != nil {
log.Fatal(err)
}
if capability.Status == shadway.CapabilityStatusActive &&
capability.ExecutionMode == shadway.CapabilityExecutionModeAvailable {
fmt.Println(capability.Name, "-", capability.Description)
}
}Configure a capability
capabilityConfig on the agent sets options for capabilities the agent already
has. It never grants a capability. An entry here does nothing on its own without
the grant.
const updated = await shadway.agents.update(agent.id, {
capabilities: ["email.send", "email.get_delivery", "phone.call", "phone.get_call", "phone"],
capabilityConfig: {
phone: { country: "US", areaCode: "302" },
},
});country := "US"
areaCode := "302"
updated, err := client.Agents.Update(ctx, agent.ID, shadway.AgentUpdateParams{
Capabilities: []string{
"email.send", "email.get_delivery", "phone.call", "phone.get_call", "phone",
},
CapabilityConfig: &shadway.AgentCapabilityConfigMap{
"phone": {Country: &country, AreaCode: &areaCode},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(updated.ID) // Same agent, new configuration revision.The phone entry in the agent's capability list is what tells Shadway to get a
phone number, and it holds the settings for it. The dotted action names are what a
mandate can actually grant.
- Phone:
country(a two-letter country code) andareaCodesay what kind of number you'd prefer.resourceuses a number you already have instead of getting a new one. - Browser:
modelon thebrowserkey runs browser work on a different model, which has to handle images and tools. Leave it out and browser work uses the default.
Getting a resource ready takes time. After you create or update an agent, read it
back and check capabilityStatus. Each entry is provisioning, requires_action,
ready, unavailable, or failed, with a detail for anything that isn't ready.
Phone goes through real setup and shows its number once it's ready. A capability
that has nothing to set up is ready as soon as the agent has it. A connected
mailbox's health shows up on its source, not here, so check the workspace's sources
if mailbox actions start failing.
Define your own capability
Your own capabilities work the same way as built-in ones: a dotted name, input and output schemas, and a declared risk, effect, verification, and idempotency. For a step-by-step, see Define your own capability.
Registering only defines the capability. In the current preview, capabilities you
host yourself can't run. A registered capability stays
executionMode: "unavailable" until something is set up to run it, and mandates
can't grant it before then.