Skip to content

Commit ee67c94

Browse files
authored
feat(sdk): added scorers to OO SDK (#679)
* feat(sdk): added scorers to OO SDK * added smoketest * added missing static create method * updated to reflect feedback * improved example embedding * feedback from review comments * add mock for create * extra tests for coverage
1 parent 392007d commit ee67c94

9 files changed

Lines changed: 768 additions & 0 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ The SDK provides object-oriented interfaces for all major Runloop resources:
6161
- **[`runloop.blueprint`](https://runloopai.github.io/api-client-ts/stable/classes/BlueprintOps.html)** - Blueprint management (create, list, build blueprints)
6262
- **[`runloop.snapshot`](https://runloopai.github.io/api-client-ts/stable/classes/SnapshotOps.html)** - Snapshot management (list disk snapshots)
6363
- **[`runloop.storageObject`](https://runloopai.github.io/api-client-ts/stable/classes/StorageObjectOps.html)** - Storage object management (upload, download, list objects)
64+
- **[`runloop.scorer`](https://runloopai.github.io/api-client-ts/stable/classes/ScorerOps.html)** - Scorer management (create, list, validate, update)
6465
- **[`runloop.api`](https://runloopai.github.io/api-client-ts/stable/classes/Runloop.html)** - Direct access to the REST API client
6566

6667
## TypeScript Support
@@ -74,6 +75,25 @@ const runloop = new RunloopSDK();
7475
const devbox: DevboxView = await runloop.devbox.create();
7576
```
7677

78+
### Scorers
79+
80+
Scorers are custom scoring functions used to evaluate scenario outputs. Create scorers via `runloop.scorer.create()`, then update or validate them with the returned `Scorer` instance:
81+
82+
```typescript
83+
import { RunloopSDK } from '@runloop/api-client';
84+
85+
const runloop = new RunloopSDK();
86+
87+
const scorer = await runloop.scorer.create({
88+
type: 'my_scorer',
89+
bash_script: 'echo "1.0"',
90+
});
91+
92+
await scorer.update({ bash_script: 'echo "0.5"' });
93+
const result = await scorer.validate({ scoring_context: { output: 'hello' } });
94+
console.log(result.scoring_result.score);
95+
```
96+
7797
## Migration from API Client
7898

7999
If you're currently using the legacy API, migration is straightforward:

src/sdk.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Blueprint, type CreateParams as BlueprintCreateParams } from './sdk/blu
66
import { Snapshot } from './sdk/snapshot';
77
import { StorageObject } from './sdk/storage-object';
88
import { Agent } from './sdk/agent';
9+
import { Scorer } from './sdk/scorer';
910

1011
// Import types used in this file
1112
import type {
@@ -17,6 +18,7 @@ import type {
1718
import type { BlueprintListParams } from './resources/blueprints';
1819
import type { ObjectCreateParams, ObjectListParams } from './resources/objects';
1920
import type { AgentCreateParams, AgentListParams } from './resources/agents';
21+
import type { ScorerCreateParams, ScorerListParams } from './resources/scenarios/scorers';
2022
import { PollingOptions } from './lib/polling';
2123
import * as Shared from './resources/shared';
2224

@@ -190,6 +192,7 @@ type ContentType = ObjectCreateParams['content_type'];
190192
* - `snapshot` - {@link SnapshotOps}
191193
* - `storageObject` - {@link StorageObjectOps}
192194
* - `agent` - {@link AgentOps}
195+
* - `scorer` - {@link ScorerOps}
193196
*
194197
* See the documentation for each Operations class for more details.
195198
*
@@ -260,6 +263,14 @@ export class RunloopSDK {
260263
*/
261264
public readonly agent: AgentOps;
262265

266+
/**
267+
* **Scorer Operations** - {@link ScorerOps} for creating and accessing {@link Scorer} class instances.
268+
*
269+
* Scorers are custom scoring functions that evaluate scenario outputs. They define scripts
270+
* that produce a score in the range [0.0, 1.0] for scenario runs.
271+
*/
272+
public readonly scorer: ScorerOps;
273+
263274
/**
264275
* Creates a new RunloopSDK instance.
265276
* @param {ClientOptions} [options] - Optional client configuration options.
@@ -271,6 +282,7 @@ export class RunloopSDK {
271282
this.snapshot = new SnapshotOps(this.api);
272283
this.storageObject = new StorageObjectOps(this.api);
273284
this.agent = new AgentOps(this.api);
285+
this.scorer = new ScorerOps(this.api);
274286
}
275287
}
276288

@@ -1255,6 +1267,121 @@ export class AgentOps {
12551267
}
12561268
}
12571269

1270+
/**
1271+
* Scorer SDK interface for managing custom scorers.
1272+
*
1273+
* @category Scorer
1274+
*
1275+
* @remarks
1276+
* ## Overview
1277+
*
1278+
* Scorers are custom scoring functions used to evaluate scenario outputs. A scorer is a
1279+
* script that runs and prints a score in the range [0.0, 1.0], e.g. `echo "0.5"`.
1280+
*
1281+
* ## Usage
1282+
*
1283+
* This interface is accessed via {@link RunloopSDK.scorer}. Create scorers with {@link ScorerOps.create}
1284+
* or reference an existing scorer by ID with {@link ScorerOps.fromId} to obtain a {@link Scorer} instance.
1285+
*
1286+
* @example
1287+
* ```typescript
1288+
* import { RunloopSDK } from '@runloop/api-client';
1289+
*
1290+
* const runloop = new RunloopSDK();
1291+
*
1292+
* // Create a scorer
1293+
* const scorer = await runloop.scorer.create({
1294+
* type: 'my_scorer',
1295+
* bash_script: 'echo "1.0"',
1296+
* });
1297+
*
1298+
* // Update the scorer
1299+
* await scorer.update({ bash_script: 'echo "0.5"' });
1300+
*
1301+
* // Validate the scorer with a scoring context
1302+
* const result = await scorer.validate({ scoring_context: { output: 'hello' } });
1303+
* console.log(result.scoring_result.score);
1304+
* ```
1305+
*
1306+
* @example
1307+
* Get scorer info (typical usage):
1308+
* ```typescript
1309+
* const runloop = new RunloopSDK();
1310+
* const scorer = await runloop.scorer.create({
1311+
* type: 'my_scorer',
1312+
* bash_script: 'echo "1.0"',
1313+
* });
1314+
*
1315+
* const info = await scorer.getInfo();
1316+
* console.log(`Scorer ${info.id} (${info.type})`);
1317+
* ```
1318+
*/
1319+
export class ScorerOps {
1320+
/**
1321+
* @private
1322+
*/
1323+
constructor(private client: RunloopAPI) {}
1324+
1325+
/**
1326+
* Create a new custom scorer.
1327+
*
1328+
* @example
1329+
* ```typescript
1330+
* const runloop = new RunloopSDK();
1331+
* const scorer = await runloop.scorer.create({
1332+
* type: 'my_scorer',
1333+
* bash_script: 'echo "1.0"',
1334+
* });
1335+
*
1336+
* const info = await scorer.getInfo();
1337+
* console.log(info.id);
1338+
* ```
1339+
*
1340+
* @param {ScorerCreateParams} params - Parameters for creating the scorer
1341+
* @param {Core.RequestOptions} [options] - Request options
1342+
* @returns {Promise<Scorer>} A {@link Scorer} instance
1343+
*/
1344+
async create(params: ScorerCreateParams, options?: Core.RequestOptions): Promise<Scorer> {
1345+
return Scorer.create(this.client, params, options);
1346+
}
1347+
1348+
/**
1349+
* Get a scorer object by its ID.
1350+
*
1351+
* @example
1352+
* ```typescript
1353+
* const runloop = new RunloopSDK();
1354+
* const scorer = runloop.scorer.fromId('scs_123');
1355+
* const info = await scorer.getInfo();
1356+
* console.log(info.type);
1357+
* ```
1358+
*
1359+
* @param {string} id - The ID of the scorer
1360+
* @returns {Scorer} A {@link Scorer} instance
1361+
*/
1362+
fromId(id: string): Scorer {
1363+
return Scorer.fromId(this.client, id);
1364+
}
1365+
1366+
/**
1367+
* List all scorers with optional filters.
1368+
*
1369+
* @example
1370+
* ```typescript
1371+
* const runloop = new RunloopSDK();
1372+
* const scorers = await runloop.scorer.list({ limit: 10 });
1373+
* console.log(scorers.map((s) => s.id));
1374+
* ```
1375+
*
1376+
* @param {ScorerListParams} [params] - Optional filter parameters
1377+
* @param {Core.RequestOptions} [options] - Request options
1378+
* @returns {Promise<Scorer[]>} An array of {@link Scorer} instances
1379+
*/
1380+
async list(params?: ScorerListParams, options?: Core.RequestOptions): Promise<Scorer[]> {
1381+
return Scorer.list(this.client, params, options);
1382+
}
1383+
}
1384+
12581385
// @deprecated Use {@link RunloopSDK} instead.
12591386
/**
12601387
* @deprecated Use {@link RunloopSDK} instead.
@@ -1275,11 +1402,13 @@ export declare namespace RunloopSDK {
12751402
SnapshotOps as SnapshotOps,
12761403
StorageObjectOps as StorageObjectOps,
12771404
AgentOps as AgentOps,
1405+
ScorerOps as ScorerOps,
12781406
Devbox as Devbox,
12791407
Blueprint as Blueprint,
12801408
Snapshot as Snapshot,
12811409
StorageObject as StorageObject,
12821410
Agent as Agent,
1411+
Scorer as Scorer,
12831412
};
12841413
}
12851414
// Export SDK classes from sdk/sdk.ts - these are separate from RunloopSDK to avoid circular dependencies
@@ -1293,6 +1422,7 @@ export {
12931422
Snapshot,
12941423
StorageObject,
12951424
Agent,
1425+
Scorer,
12961426
Execution,
12971427
ExecutionResult,
12981428
} from './sdk/index';

src/sdk/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { StorageObject } from './storage-object';
55
export { Agent } from './agent';
66
export { Execution } from './execution';
77
export { ExecutionResult } from './execution-result';
8+
export { Scorer } from './scorer';

0 commit comments

Comments
 (0)