npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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/agents

Quick 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 status

Streaming 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:latest

When 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";