Agent routing server
A habitat for your agents.
Connect agents over WebSocket. Serpentary routes their tasks by policy and queues work while the target agent is offline.
Closed beta
See the SDKWhat Serpentary handles
Agents in any language
Use the JavaScript or Go SDK, or implement the JSON protocol in another language. Agents run as ordinary processes.
Routing by policy
Policies map aliases to exact agent versions. Serpentary distributes requests round-robin across connected instances of that version.
Offline queues
Tasks wait on the server until an instance of the target agent connects.
Response delivery
Responses return to the instance that called, including after it reconnects. Delivery is at least once per task ID; SDKs discard duplicates.
JavaScript sandbox
Serpentary can run JavaScript agents in an embedded sandbox with a time limit. The sandbox accesses other services through ctx and has no direct filesystem or network access.
Sessions, storage and schedules
Sessions share policies and context across calls and stream progress to callers. Each company has JSON storage and one-off or cron schedules.
How a task travels
Step 1 · Connect Each agent opens a WebSocket connection to Serpentary.
Step 2 · Route The caller requests an alias. The session's policy selects agent@version, then Serpentary picks one of its connected instances.
Step 3 · Wait If every instance is offline, the task stays in the queue.
Step 4 · Deliver When an instance reconnects, it takes the queued task. Serpentary sends the response back to the caller, holding it if the caller is offline.
Write an agent
This greeter calls a translator agent and returns its reply.
JavaScript: greeter.js
import { Serpentary, Agent } from '@automatica-ai/serpentary-sdk'
// An agent is a name, an exact version and its actions.
const greeter = new Agent('greeter', '1.0.0', { description: 'Greets people in their language' }, [
{
name: 'greet',
parameters: {
type: 'object',
properties: { name: { type: 'string' }, lang: { type: 'string' } },
required: ['name', 'lang'],
},
handler: async ({ name, lang }, ctx) => {
ctx.say('translating…') // progress travels up the call tree
// 'translator' is an alias: the session's policy picks agent@version.
const reply = await ctx.agents.translator('translate', { text: `Hello, ${name}!`, to: lang })
return { greeting: reply.text } // return = response, throw = error
},
},
])
await Serpentary.connect({
url: 'wss://serpentary.com',
companySlug: process.env.COMPANY_SLUG,
uuid: process.env.CLIENT_UUID,
token: process.env.CLIENT_TOKEN,
agents: [greeter],
})
Go: main.go
package main
import (
"fmt"
"log"
"os"
"github.com/automatica-ai/serpentary-sdk-go/serpentary"
)
func main() {
// An agent is a name, an exact version and its actions.
greeter := serpentary.NewAgent("greeter", "1.0.0").
WithDescription("Greets people in their language").
Action("greet", serpentary.ActionConfig{
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]any{"type": "string"},
"lang": map[string]any{"type": "string"},
},
"required": []string{"name", "lang"},
},
Handler: func(ctx *serpentary.Context, params map[string]any) (any, error) {
ctx.Say("translating…") // progress travels up the call tree
// "translator" is an alias: the session's policy picks agent@version.
result, err := ctx.Agents.Call("translator", "translate", map[string]any{
"text": fmt.Sprintf("Hello, %v!", params["name"]),
"to": params["lang"],
})
if err != nil {
return nil, err // the caller receives an error
}
reply, ok := result.(map[string]any)
if !ok {
return nil, fmt.Errorf("unexpected translator reply: %v", result)
}
return map[string]any{"greeting": reply["text"]}, nil
},
})
client, err := serpentary.Connect(serpentary.Config{
URL: "wss://serpentary.com",
CompanySlug: os.Getenv("COMPANY_SLUG"),
UUID: os.Getenv("CLIENT_UUID"),
Token: os.Getenv("CLIENT_TOKEN"),
Agents: []*serpentary.Agent{greeter},
})
if err != nil {
log.Fatal(err)
}
client.Wait()
}
Access by invitation
An administrator can invite you by GitHub username or verified email. If you already have an invitation, sign in with GitHub.
Sign in