Skip to content

Commit 20df292

Browse files
jrvb-rlwall-rl
andauthored
Add Agents to OO TypeScript SDK (#669)
* cp * cp * cp * add unittests and smoketests --------- Co-authored-by: wall <wall@runloop.ai>
1 parent 0ca3940 commit 20df292

10 files changed

Lines changed: 9400 additions & 605 deletions

File tree

package-lock.json

Lines changed: 8021 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@swc/core": "^1.3.102",
5858
"@swc/jest": "^0.2.29",
5959
"@types/jest": "^29.4.0",
60+
"@types/tar": "^6.1.13",
6061
"@typescript-eslint/eslint-plugin": "^6.7.0",
6162
"@typescript-eslint/parser": "^6.7.0",
6263
"eslint": "^8.49.0",

src/sdk.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Devbox } from './sdk/devbox';
55
import { Blueprint, type CreateParams as BlueprintCreateParams } from './sdk/blueprint';
66
import { Snapshot } from './sdk/snapshot';
77
import { StorageObject } from './sdk/storage-object';
8+
import { Agent } from './sdk/agent';
89

910
// Import types used in this file
1011
import type {
@@ -15,6 +16,7 @@ import type {
1516
} from './resources/devboxes/devboxes';
1617
import type { BlueprintListParams } from './resources/blueprints';
1718
import type { ObjectCreateParams, ObjectListParams } from './resources/objects';
19+
import type { AgentCreateParams, AgentListParams } from './resources/agents';
1820
import { PollingOptions } from './lib/polling';
1921

2022
export * from './index';
@@ -48,6 +50,7 @@ type ContentType = ObjectCreateParams['content_type'];
4850
* - `blueprint` - {@link BlueprintOps}
4951
* - `snapshot` - {@link SnapshotOps}
5052
* - `storageObject` - {@link StorageObjectOps}
53+
* - `agent` - {@link AgentOps}
5154
*
5255
* See the documentation for each Operations class for more details.
5356
*
@@ -109,6 +112,15 @@ export class RunloopSDK {
109112
*/
110113
public readonly storageObject: StorageObjectOps;
111114

115+
/**
116+
* **Agent Operations** - {@link AgentOps} for creating and accessing {@link Agent} class instances.
117+
*
118+
* Agents are registered AI agent entities that can be mounted into devboxes. Agents can be sourced
119+
* from npm, pip, git repositories, or object storage, and provide reusable agent code that can be
120+
* shared across multiple devboxes. Use these operations to create new agents or get existing ones by ID.
121+
*/
122+
public readonly agent: AgentOps;
123+
112124
/**
113125
* Creates a new RunloopSDK instance.
114126
* @param {ClientOptions} [options] - Optional client configuration options.
@@ -119,6 +131,7 @@ export class RunloopSDK {
119131
this.blueprint = new BlueprintOps(this.api);
120132
this.snapshot = new SnapshotOps(this.api);
121133
this.storageObject = new StorageObjectOps(this.api);
134+
this.agent = new AgentOps(this.api);
122135
}
123136
}
124137

@@ -615,6 +628,75 @@ export class StorageObjectOps {
615628
}
616629
}
617630

631+
/**
632+
* Agent SDK interface for managing agents.
633+
*
634+
* ## Overview
635+
*
636+
* The `AgentOps` class provides a high-level abstraction for managing AI agent entities.
637+
* Agents can be sourced from npm, pip, git repositories, or object storage, and mounted
638+
* into devboxes for execution.
639+
*
640+
* ## Usage
641+
*
642+
* This interface is accessed via {@link RunloopSDK.agent}. You should construct
643+
* a {@link RunloopSDK} instance and use it from there:
644+
*
645+
* @example
646+
* ```typescript
647+
* const sdk = new RunloopSDK();
648+
* const agent = await sdk.agent.create({
649+
* name: 'my-npm-agent',
650+
* source: {
651+
* type: 'npm',
652+
* npm: { package_name: '@my-org/agent' }
653+
* }
654+
* });
655+
* const devbox = await agent.createDevbox({
656+
* name: 'devbox-with-agent',
657+
* agent_path: '/home/user/agent'
658+
* });
659+
* ```
660+
*/
661+
export class AgentOps {
662+
/**
663+
* @private
664+
*/
665+
constructor(private client: RunloopAPI) {}
666+
667+
/**
668+
* Create a new agent.
669+
*
670+
* @param {AgentCreateParams} params - Parameters for creating the agent.
671+
* @param {Core.RequestOptions} [options] - Request options.
672+
* @returns {Promise<Agent>} An {@link Agent} instance.
673+
*/
674+
async create(params: AgentCreateParams, options?: Core.RequestOptions): Promise<Agent> {
675+
return Agent.create(this.client, params, options);
676+
}
677+
678+
/**
679+
* Get an agent object by its ID.
680+
*
681+
* @param {string} id - The ID of the agent.
682+
* @returns {Agent} An {@link Agent} instance.
683+
*/
684+
fromId(id: string): Agent {
685+
return Agent.fromId(this.client, id);
686+
}
687+
688+
/**
689+
* List all agents with optional filters.
690+
*
691+
* @param {AgentListParams} [params] - Optional filter parameters.
692+
* @param {Core.RequestOptions} [options] - Request options.
693+
* @returns {Promise<Agent[]>} An array of {@link Agent} instances.
694+
*/
695+
async list(params?: AgentListParams, options?: Core.RequestOptions): Promise<Agent[]> {
696+
return Agent.list(this.client, params, options);
697+
}
698+
}
699+
618700
// @deprecated Use {@link RunloopSDK} instead.
619701
/**
620702
* @deprecated Use {@link RunloopSDK} instead.
@@ -634,10 +716,12 @@ export declare namespace RunloopSDK {
634716
BlueprintOps as BlueprintOps,
635717
SnapshotOps as SnapshotOps,
636718
StorageObjectOps as StorageObjectOps,
719+
AgentOps as AgentOps,
637720
Devbox as Devbox,
638721
Blueprint as Blueprint,
639722
Snapshot as Snapshot,
640723
StorageObject as StorageObject,
724+
Agent as Agent,
641725
};
642726
}
643727
// Export SDK classes from sdk/sdk.ts - these are separate from RunloopSDK to avoid circular dependencies
@@ -650,6 +734,7 @@ export {
650734
Blueprint,
651735
Snapshot,
652736
StorageObject,
737+
Agent,
653738
Execution,
654739
ExecutionResult,
655740
} from './sdk/index';

src/sdk/agent.ts

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { Runloop } from '../index';
2+
import type * as Core from '../core';
3+
import type { AgentCreateParams, AgentListParams, AgentView } from '../resources/agents';
4+
5+
/**
6+
* Object-oriented interface for working with Agents.
7+
*
8+
* ## Overview
9+
*
10+
* The `Agent` class provides a high-level API for managing AI agent entities.
11+
* Agents represent registered AI agents that can be mounted into devboxes and
12+
* sourced from various package managers (npm, pip), git repositories, or object storage.
13+
*
14+
* ## Quickstart
15+
*
16+
* Agents are created and then mounted into devboxes via the mounts parameter:
17+
* ```typescript
18+
* import { RunloopSDK } from '@runloop/api-client-ts';
19+
*
20+
* const runloop = new RunloopSDK();
21+
*
22+
* // Create an agent from git
23+
* const agent = await runloop.agent.create({
24+
* name: 'my-agent',
25+
* source: {
26+
* type: 'git',
27+
* git: {
28+
* repository: 'https://github.com/user/agent-repo',
29+
* ref: 'main'
30+
* }
31+
* }
32+
* });
33+
*
34+
* // Mount agent into a devbox
35+
* const devbox = await runloop.devbox.create({
36+
* name: 'devbox-with-agent',
37+
* mounts: [{
38+
* type: 'agent_mount',
39+
* agent_id: agent.id,
40+
* agent_path: '/home/user/agent'
41+
* }]
42+
* });
43+
* ```
44+
*
45+
*/
46+
export class Agent {
47+
private client: Runloop;
48+
private _id: string;
49+
50+
constructor(client: Runloop, id: string) {
51+
this.client = client;
52+
this._id = id;
53+
}
54+
55+
/**
56+
* Create an Agent instance by ID without retrieving from API.
57+
* Use getInfo() to fetch the actual data when needed.
58+
*
59+
* See the {@link AgentOps.fromId} method for calling this
60+
* @private
61+
*
62+
* @param {Runloop} client - The Runloop client instance
63+
* @param {string} id - The agent ID
64+
* @returns {Agent} An {@link Agent} instance
65+
*/
66+
static fromId(client: Runloop, id: string): Agent {
67+
return new Agent(client, id);
68+
}
69+
70+
/**
71+
* Create a new Agent.
72+
*
73+
* See the {@link AgentOps.create} method for calling this
74+
* @private
75+
*
76+
* @param {Runloop} client - The Runloop client instance
77+
* @param {AgentCreateParams} params - Agent creation parameters
78+
* @param {Core.RequestOptions} [options] - Request options
79+
* @returns {Promise<Agent>} A new {@link Agent} instance
80+
*/
81+
static async create(
82+
client: Runloop,
83+
params: AgentCreateParams,
84+
options?: Core.RequestOptions,
85+
): Promise<Agent> {
86+
const agentData = await client.agents.create(params, options);
87+
return new Agent(client, agentData.id);
88+
}
89+
90+
/**
91+
* List all agents, optionally filtered by name, public status, or search query.
92+
*
93+
* @example
94+
* ```typescript
95+
* const runloop = new RunloopSDK();
96+
* // List all agents
97+
* const agents = await runloop.agent.list();
98+
*
99+
* // Filter by name
100+
* const agents = await runloop.agent.list({ name: 'my-agent' });
101+
*
102+
* // Search by ID or name
103+
* const agents = await runloop.agent.list({ search: 'agent-123' });
104+
* ```
105+
*
106+
* @param {Runloop} client - The Runloop client instance
107+
* @param {AgentListParams} [params] - Optional filter parameters
108+
* @param {Core.RequestOptions} [options] - Request options
109+
* @returns {Promise<Agent[]>} Array of {@link Agent} instances
110+
*/
111+
static async list(
112+
client: Runloop,
113+
params?: AgentListParams,
114+
options?: Core.RequestOptions,
115+
): Promise<Agent[]> {
116+
const agents = await client.agents.list(params, options);
117+
const result: Agent[] = [];
118+
119+
for await (const agent of agents) {
120+
result.push(new Agent(client, agent.id));
121+
}
122+
123+
return result;
124+
}
125+
126+
/**
127+
* Get the agent ID.
128+
*/
129+
get id(): string {
130+
return this._id;
131+
}
132+
133+
/**
134+
* Get the complete agent data from the API.
135+
*
136+
* @param {Core.RequestOptions} [options] - Request options
137+
* @returns {Promise<AgentView>} The agent data
138+
*/
139+
async getInfo(options?: Core.RequestOptions): Promise<AgentView> {
140+
return await this.client.agents.retrieve(this._id, options);
141+
}
142+
}

src/sdk/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ export { Devbox, DevboxCmdOps, DevboxFileOps, DevboxNetOps, type ExecuteStreamin
22
export { Blueprint } from './blueprint';
33
export { Snapshot } from './snapshot';
44
export { StorageObject } from './storage-object';
5+
export { Agent } from './agent';
56
export { Execution } from './execution';
67
export { ExecutionResult } from './execution-result';

0 commit comments

Comments
 (0)