Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/resources/axons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,17 @@ export class Axons extends APIResource {
* [Beta] Subscribe to an axon event stream via server-sent events.
*/
subscribeSse(id: string, options?: Core.RequestOptions): APIPromise<Stream<AxonEventView>> {
return this._client.get(`/v1/axons/${id}/subscribe/sse`, { ...options, stream: true }) as APIPromise<
Stream<AxonEventView>
>;
const defaultHeaders = {
Accept: 'text/event-stream',
};
const mergedOptions: Core.RequestOptions = {
headers: defaultHeaders,
...options,
};
Comment on lines +57 to +60
Copy link
Copy Markdown
Contributor

@sid-rl sid-rl Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this drop defaultHeaders if user provides any headers? we should make this headers: {Accept: 'text/event-stream', ...options?.headers,}

return this._client.get(`/v1/axons/${id}/subscribe/sse`, {
...mergedOptions,
stream: true,
}) as APIPromise<Stream<AxonEventView>>;
}
}

Expand Down
92 changes: 92 additions & 0 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Blueprint, type CreateParams as BlueprintCreateParams } from './sdk/blu
import { Snapshot } from './sdk/snapshot';
import { StorageObject } from './sdk/storage-object';
import { Agent } from './sdk/agent';
import { Axon } from './sdk/axon';
import { Scorer } from './sdk/scorer';
import { NetworkPolicy } from './sdk/network-policy';
import { GatewayConfig } from './sdk/gateway-config';
Expand All @@ -23,6 +24,7 @@ import type {
import type { BlueprintListParams } from './resources/blueprints';
import type { ObjectCreateParams, ObjectListParams } from './resources/objects';
import type { AgentCreateParams, AgentListParams } from './resources/agents';
import type { AxonCreateParams } from './resources/axons';
import type { ScorerCreateParams, ScorerListParams } from './resources/scenarios/scorers';
import type { NetworkPolicyCreateParams, NetworkPolicyListParams } from './resources/network-policies';
import type { GatewayConfigCreateParams, GatewayConfigListParams } from './resources/gateway-configs';
Expand Down Expand Up @@ -369,6 +371,7 @@ type ContentType = ObjectCreateParams['content_type'];
* - `snapshot` - {@link SnapshotOps}
* - `storageObject` - {@link StorageObjectOps}
* - `agent` - {@link AgentOps}
* - `axon` - {@link AxonOps}
* - `scorer` - {@link ScorerOps}
* - `networkPolicy` - {@link NetworkPolicyOps}
* - `gatewayConfig` - {@link GatewayConfigOps}
Expand Down Expand Up @@ -433,6 +436,15 @@ export class RunloopSDK {
*/
public readonly agent: AgentOps;

/**
* **Axon Operations** - {@link AxonOps} for creating and accessing {@link Axon} class instances.
*
* [Beta] Axons are event communication channels that support publishing events and subscribing
* to event streams via server-sent events (SSE). Use these operations to create new axons,
* get existing ones by ID, or list all active axons.
*/
public readonly axon: AxonOps;

/**
* **Scorer Operations** - {@link ScorerOps} for creating and accessing {@link Scorer} class instances.
*
Expand Down Expand Up @@ -494,6 +506,7 @@ export class RunloopSDK {
this.snapshot = new SnapshotOps(this.api);
this.storageObject = new StorageObjectOps(this.api);
this.agent = new AgentOps(this.api);
this.axon = new AxonOps(this.api);
this.scorer = new ScorerOps(this.api);
this.networkPolicy = new NetworkPolicyOps(this.api);
this.gatewayConfig = new GatewayConfigOps(this.api);
Expand Down Expand Up @@ -1484,6 +1497,82 @@ export class AgentOps {
}
}

/**
* [Beta] Axon SDK interface for managing axons.
*
* @category Axon
*
* @remarks
* ## Overview
*
* The `AxonOps` class provides a high-level abstraction for managing axons,
* which are event communication channels. Axons support publishing events
* and subscribing to event streams via server-sent events (SSE).
*
* ## Usage
*
* This interface is accessed via {@link RunloopSDK.axon}. You should construct
* a {@link RunloopSDK} instance and use it from there:
*
* @example
* ```typescript
* const runloop = new RunloopSDK();
* const axon = await runloop.axon.create();
*
* // Publish an event
* await axon.publish({
* event_type: 'task_complete',
* origin: 'AGENT_EVENT',
* payload: JSON.stringify({ result: 'success' }),
* source: 'my-agent',
* });
*
* // Subscribe to events
* const stream = await axon.subscribeSse();
* for await (const event of stream) {
* console.log(event.event_type, event.payload);
* }
* ```
*/
export class AxonOps {
/**
* @private
*/
constructor(private client: RunloopAPI) {}

/**
* [Beta] Create a new axon.
*
* @param {AxonCreateParams} [params] - Parameters for creating the axon.
* @param {Core.RequestOptions} [options] - Request options.
* @returns {Promise<Axon>} An {@link Axon} instance.
*/
async create(params?: AxonCreateParams, options?: Core.RequestOptions): Promise<Axon> {
return Axon.create(this.client, params, options);
}

/**
* Get an axon object by its ID.
*
* @param {string} id - The ID of the axon.
* @returns {Axon} An {@link Axon} instance.
*/
fromId(id: string): Axon {
return Axon.fromId(this.client, id);
}

/**
* [Beta] List all active axons.
*
* @param {Core.RequestOptions} [options] - Request options.
* @returns {Promise<Axon[]>} An array of {@link Axon} instances.
*/
async list(options?: Core.RequestOptions): Promise<Axon[]> {
const result = await this.client.axons.list(options);
return result.axons.map((axon) => Axon.fromId(this.client, axon.id));
}
}

/**
* Scorer SDK interface for managing custom scorers.
*
Expand Down Expand Up @@ -2199,6 +2288,7 @@ export declare namespace RunloopSDK {
SnapshotOps as SnapshotOps,
StorageObjectOps as StorageObjectOps,
AgentOps as AgentOps,
AxonOps as AxonOps,
ScorerOps as ScorerOps,
NetworkPolicyOps as NetworkPolicyOps,
GatewayConfigOps as GatewayConfigOps,
Expand All @@ -2210,6 +2300,7 @@ export declare namespace RunloopSDK {
Snapshot as Snapshot,
StorageObject as StorageObject,
Agent as Agent,
Axon as Axon,
Scorer as Scorer,
NetworkPolicy as NetworkPolicy,
GatewayConfig as GatewayConfig,
Expand All @@ -2229,6 +2320,7 @@ export {
Snapshot,
StorageObject,
Agent,
Axon,
Scorer,
NetworkPolicy,
McpConfig,
Expand Down
137 changes: 137 additions & 0 deletions src/sdk/axon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { Runloop } from '../index';
import type * as Core from '../core';
import { Stream } from '../streaming';
import type {
AxonView,
AxonCreateParams,
AxonPublishParams,
PublishResultView,
AxonEventView,
} from '../resources/axons';

/**
* [Beta] Object-oriented interface for working with Axons.
*
* @category Axon
*
* @remarks
* ## Overview
*
* The `Axon` class provides a high-level, object-oriented API for managing axons.
* Axons are event communication channels that support publishing events and subscribing
* to event streams via server-sent events (SSE).
*
* ## Quickstart
*
* ```typescript
* import { RunloopSDK } from '@runloop/api-client';
*
* const runloop = new RunloopSDK();
* const axon = await runloop.axon.create();
*
* // Publish an event
* await axon.publish({
* event_type: 'task_complete',
* origin: 'AGENT_EVENT',
* payload: JSON.stringify({ result: 'success' }),
* source: 'my-agent',
* });
*
* // Subscribe to events
* const stream = await axon.subscribeSse();
* for await (const event of stream) {
* console.log(event.event_type, event.payload);
* }
* ```
*/
export class Axon {
private client: Runloop;
private _id: string;

private constructor(client: Runloop, id: string) {
this.client = client;
this._id = id;
}

/**
* [Beta] Create a new Axon.
*
* See the {@link AxonOps.create} method for calling this
* @private
*
* @param {Runloop} client - The Runloop client instance
* @param {AxonCreateParams} [params] - Parameters for creating the axon
* @param {Core.RequestOptions} [options] - Request options
* @returns {Promise<Axon>} An {@link Axon} instance
*/
static async create(
client: Runloop,
params?: AxonCreateParams,
options?: Core.RequestOptions,
): Promise<Axon> {
const axonData = await client.axons.create(params ?? {}, options);
return new Axon(client, axonData.id);
}

/**
* Create an Axon instance by ID without retrieving from API.
* Use getInfo() to fetch the actual data when needed.
*
* See the {@link AxonOps.fromId} method for calling this
* @private
*
* @param {Runloop} client - The Runloop client instance
* @param {string} id - The axon ID
* @returns {Axon} An {@link Axon} instance
*/
static fromId(client: Runloop, id: string): Axon {
return new Axon(client, id);
}

/**
* Get the axon ID.
* @returns {string} The axon ID
*/
get id(): string {
return this._id;
}

/**
* [Beta] Get the complete axon data from the API.
*
* @param {Core.RequestOptions} [options] - Request options
* @returns {Promise<AxonView>} The axon data
*/
async getInfo(options?: Core.RequestOptions): Promise<AxonView> {
return this.client.axons.retrieve(this._id, options);
}

/**
* [Beta] Publish an event to this axon.
*
* @param {AxonPublishParams} params - Parameters for the event to publish
* @param {Core.RequestOptions} [options] - Request options
* @returns {Promise<PublishResultView>} The publish result with sequence number and timestamp
*/
async publish(params: AxonPublishParams, options?: Core.RequestOptions): Promise<PublishResultView> {
return this.client.axons.publish(this._id, params, options);
}

/**
* [Beta] Subscribe to this axon's event stream via server-sent events.
*
* @example
* ```typescript
* const stream = await axon.subscribeSse();
* for await (const event of stream) {
* console.log(`[${event.source}] ${event.event_type}: ${event.payload}`);
* }
* ```
*
* @param {Core.RequestOptions} [options] - Request options
* @returns {Promise<Stream<AxonEventView>>} An async iterable stream of axon events
*/
async subscribeSse(options?: Core.RequestOptions): Promise<Stream<AxonEventView>> {
return this.client.axons.subscribeSse(this._id, options);
}
}
1 change: 1 addition & 0 deletions src/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { Blueprint } from './blueprint';
export { Snapshot } from './snapshot';
export { StorageObject } from './storage-object';
export { Agent } from './agent';
export { Axon } from './axon';
export { Execution } from './execution';
export { ExecutionResult } from './execution-result';
export { Scorer } from './scorer';
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export type * from './resources/blueprints';

export type * from './resources/agents';

// =============================================================================
// Axon Types
// =============================================================================

export type * from './resources/axons';

// =============================================================================
// Storage Object Types
// =============================================================================
Expand Down
Loading
Loading