@trelent/agents
v0.2.7
Published
TypeScript SDK for the Trelent Agent Orchestration API.
Readme
@trelent/agents
TypeScript SDK for the Trelent Agent Orchestration API.
Installation
npm install @trelent/agents
# or
bun add @trelent/agentsQuick Start
Without authentication
import { Client } from "@trelent/agents";
const client = new Client("http://localhost:8000");
const sandboxes = await client.sandboxes.list();
console.log(sandboxes);
const run = await client.runs.create({
sandbox: "example-agent:latest",
prompt: "Create hello.txt with a greeting",
});
console.log(run.id, run.status, run.harness.kind);With authentication
When the API has authentication enabled, provide your OAuth2 client credentials:
import { Client } from "@trelent/agents";
const client = new Client("https://agents.trelent.com", {
clientId: "your-client-id",
clientSecret: "your-client-secret",
});
const sandboxes = await client.sandboxes.list();
const run = await client.runs.create({
sandbox: "my-sandbox:latest",
prompt: "Do something useful",
});The SDK handles token acquisition automatically — it exchanges your client credentials for a JWT via the API's /token endpoint before making authenticated requests.
If you need to call the token proxy directly, use client.tokens.create(...).
Client Options
const client = new Client(apiUrl, {
clientId: "...", // OAuth2 client ID (optional)
clientSecret: "...", // OAuth2 client secret (optional)
scope: "...", // Override default OAuth2 scope (optional)
timeoutMs: 10_000, // Request timeout in ms (default: 10000)
});Both clientId and clientSecret must be provided together, or both omitted.
Resources
client.sandboxes
const sandboxes = await client.sandboxes.list();
// => RegistrySandbox[] — [{ name: "my-sandbox", tags: ["latest", "v1"] }]When auth is enabled, sandboxes are automatically filtered to your namespace. Sandbox names are returned without the namespace prefix.
client.tokens
const token = await client.tokens.create({
client_id: "your-client-id",
client_secret: "your-client-secret",
scope: "AgentOrchestrator:runs:list",
});client.runs
import { HarnessKind, LocalImporter, S3Exporter } from "@trelent/agents";
// Create a run
const run = await client.runs.create({
sandbox: "my-sandbox:latest",
prompt: "Build a web server",
harness: { kind: HarnessKind.ClaudeCode }, // optional, defaults to Claude Code
timeout_seconds: 3600, // optional, default: 3600
imports: [new LocalImporter("./data")], // optional
exports: [new S3Exporter()], // optional
});
// List runs (optionally filter by sandbox)
const runs = await client.runs.list();
const filtered = await client.runs.list("my-sandbox:latest");
// Get a specific run
const run = await client.runs.get("run-id");
// Check status
const status = await client.runs.getStatus("run-id");
// Cancel a run
const cancel = await client.runs.cancel("run-id");
// Get checkpoints
const chain = await client.runs.getCheckpointChain("run-id");
const checkpoint = await client.runs.getCheckpoint("run-id", "checkpoint-id");Run operations
// Fork (resume from checkpoint)
const forked = await run.fork("Continue from where you left off", {
timeout_seconds: 1800,
});
// Refresh run state
await run.refresh();
console.log(run.status); // updated statusStreaming Events
Subscribe to real-time events from a run using Server-Sent Events (SSE). Events are streamed as the agent executes, providing live visibility into reasoning, messages, and tool usage.
Basic streaming
import { Client, EventType } from "@trelent/agents";
const client = new Client(apiUrl, { clientId, clientSecret });
const run = await client.runs.create({
sandbox: "my-sandbox:latest",
prompt: "Build a simple web server",
});
// Subscribe to the event stream
const stream = run.subscribe();
for await (const event of stream) {
switch (event.type) {
case EventType.MessageDelta:
process.stdout.write(event.data.delta.text);
break;
case EventType.ToolCallStarted:
console.log(`\nTool: ${event.data.name}`);
break;
case EventType.SessionCompleted:
console.log(`\nCompleted with exit code: ${event.data.exit_code}`);
break;
}
}Subscribing via client
You can also subscribe using the run ID directly:
const stream = client.runs.subscribe("run-abc123");
for await (const event of stream) {
console.log(event.type, event.seq);
}Closing the stream
The stream automatically closes when the run completes. To close early:
const stream = run.subscribe();
for await (const event of stream) {
if (someCondition) {
stream.close(); // Unsubscribe and close connection
break;
}
}Event types
| Event Type | Description |
|------------|-------------|
| session.started | Agent session initialized |
| session.completed | Session finished (includes exit_code and usage) |
| turn.started | New conversation turn began |
| turn.completed | Turn finished |
| turn.failed | Turn failed with error |
| message.started | Assistant message started |
| message.delta | Incremental text content |
| message.completed | Full message content available |
| reasoning.started | Extended thinking started |
| reasoning.delta | Incremental reasoning text |
| reasoning.completed | Reasoning block finished |
| tool_call.started | Tool invocation started (includes name and kind) |
| tool_call.input_delta | Streaming tool input JSON |
| tool_call.input_complete | Full tool input available |
| tool_call.output_delta | Streaming tool output |
| tool_call.completed | Tool execution finished (includes exit_code) |
| error | Error occurred |
Event structure
Every event has a common envelope:
interface CommonEvent {
seq: number; // Sequence number (monotonically increasing)
timestamp: string; // ISO 8601 timestamp
type: EventType; // Event type discriminator
data: EventData; // Type-specific payload
}client.health()
const health = await client.health();
// => { status: "ok" }Connectors
Importing local files
import { LocalImporter } from "@trelent/agents";
const run = await client.runs.create({
sandbox: "my-sandbox:latest",
prompt: "Process the data",
imports: [new LocalImporter("./my-data-dir")],
});Exporting to S3
import { S3Exporter } from "@trelent/agents";
const run = await client.runs.create({
sandbox: "my-sandbox:latest",
prompt: "Generate a report",
exports: [new S3Exporter("my-bucket", "reports/")],
});Docker Registry Setup
When auth is enabled, push sandbox images to your user namespace on the registry:
# Login with your OAuth2 credentials
docker login registry.example.com -u <client_id> -p <client_secret>
# Push to your namespace
docker tag my-sandbox:latest registry.example.com/<client_id>/my-sandbox:latest
docker push registry.example.com/<client_id>/my-sandbox:latestWhen creating runs via the SDK, just use the sandbox name without the namespace prefix:
const run = await client.runs.create({
sandbox: "my-sandbox:latest", // not "<client_id>/my-sandbox:latest"
prompt: "...",
});The API resolves the full registry path automatically based on your authenticated identity.
Types
The SDK exports the following types:
import { EventType, HarnessKind, RunStatus, ToolKind } from "@trelent/agents";
import type {
CancelRunResponse,
ClaudeCodeHarnessSpec,
CodexHarnessSpec,
ClientOptions,
CommonEvent,
CreateRunOptions,
GeminiHarnessSpec,
RegistrySandbox,
RunResult,
RunStatusResponse,
CheckpointResponse,
ChatHistoryEntry,
FileOutput,
OutputFile,
HealthResponse,
HarnessInfo,
HarnessSpec,
ResumeRunOptions,
TokenRequest,
TokenResponse,
Usage,
WorkflowIds,
} from "@trelent/agents";