@simular-ai/sai-sdk 0.0.0-stage → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Direct control: drive a cloud computer with Simulang. No agent.
3
+ *
4
+ * Maps to `/v1/machines/{id}/control`, a lease on the machine: at most one per
5
+ * machine, so the machine id is the handle. Research preview, open to every
6
+ * account; model calls the code makes (`callLLM`, `ground`, `stateSatisfies`)
7
+ * are billed as usual.
8
+ */
9
+ import { BlockError, GoneError } from './errors.js';
10
+ import { idOf } from './machines.js';
11
+ import { parseExecResult } from './types.js';
12
+ function controlPath(machineId) {
13
+ return `/v1/machines/${encodeURIComponent(machineId)}/control`;
14
+ }
15
+ export class Control {
16
+ http;
17
+ constructor(http) {
18
+ this.http = http;
19
+ }
20
+ /**
21
+ * Take a cloud computer. Resolves once the lease holds it, up to ~3
22
+ * minutes when a Sai task holds it or it has to start; at once if the lease
23
+ * is already open. Close it when done (`await using`, or `try/finally`):
24
+ * Sai's tasks on that computer wait until then.
25
+ */
26
+ async open(opts) {
27
+ const machineId = idOf(opts.machine);
28
+ const d = await this.http.json('POST', controlPath(machineId), {
29
+ timeoutMs: 240_000,
30
+ });
31
+ return new ControlLease(this.http, machineId, Number(d.expiresAfterIdleSec ?? 0));
32
+ }
33
+ }
34
+ export class ControlLease {
35
+ http;
36
+ machineId;
37
+ idleTimeoutSec;
38
+ closed = false;
39
+ path;
40
+ constructor(http, machineId, idleTimeoutSec) {
41
+ this.http = http;
42
+ this.machineId = machineId;
43
+ this.idleTimeoutSec = idleTimeoutSec;
44
+ this.path = controlPath(machineId);
45
+ }
46
+ async [Symbol.asyncDispose]() {
47
+ await this.close();
48
+ }
49
+ /**
50
+ * Run one Simulang (JavaScript) block. Use `var` for anything the next block
51
+ * needs. A block that throws, times out or is interrupted still resolves:
52
+ * check `result.error`. Throws `GoneError` once the lease has ended (closed,
53
+ * idle, taken by a Sai task, or the computer stopped answering): open again.
54
+ */
55
+ async exec(code, opts = {}) {
56
+ const body = { code };
57
+ if (opts.timeoutMs !== undefined)
58
+ body.timeoutMs = opts.timeoutMs;
59
+ const d = await this.http.json('POST', `${this.path}/exec`, {
60
+ json: body,
61
+ timeoutMs: (opts.timeoutMs ?? 120_000) + 45_000,
62
+ });
63
+ return parseExecResult(d);
64
+ }
65
+ /**
66
+ * Run code from `sai.learn.create()`: its `main` with `inputs` over the parameters' defaults
67
+ * (an argument to `main` replaces its whole default object, so missing inputs keep their
68
+ * defaults). `main`'s return value is `result.result`. A string runs as code with `inputs` as is.
69
+ */
70
+ async run(learned, inputs = {}, opts = {}) {
71
+ const code = typeof learned === 'string' ? learned : learned.code;
72
+ const defaults = typeof learned === 'string'
73
+ ? {}
74
+ : Object.fromEntries(learned.parameters.map((p) => [p.name, p.defaultValue]));
75
+ return this.exec(`${code}\nawait main(${JSON.stringify({ ...defaults, ...inputs })})`, opts);
76
+ }
77
+ /** Run a shell command: `{ stdout, stderr, exitCode, timedOut }`. */
78
+ async shell(command, opts = {}) {
79
+ const args = { command };
80
+ if (opts.cwd)
81
+ args.cwd = opts.cwd;
82
+ const r = await this.exec(`await machine.exec(${JSON.stringify(args)})`, {
83
+ timeoutMs: opts.timeoutMs,
84
+ });
85
+ raiseOnBlockError(r);
86
+ return r.result;
87
+ }
88
+ async readFile(path) {
89
+ const r = await this.exec(`await machine.readFile(${JSON.stringify({ path })})`);
90
+ raiseOnBlockError(r);
91
+ return r.result;
92
+ }
93
+ async writeFile(path, text) {
94
+ const r = await this.exec(`await machine.writeToFile(${JSON.stringify({ path, text, overwrite: true })})`);
95
+ raiseOnBlockError(r);
96
+ }
97
+ /**
98
+ * The whole screen as image bytes (usually JPEG; use `exec` for the MIME type). Needs the
99
+ * computer's screen-capture service; throws `BlockError` where it is off (a page or app
100
+ * snapshot still carries an image).
101
+ */
102
+ async screenshot() {
103
+ const r = await this.exec('var __sai_page = await machine.pageContent(); null');
104
+ raiseOnBlockError(r);
105
+ if (!r.screenshot) {
106
+ throw new BlockError('exception', r.screenshotOmitted ? 'screenshot too large to return' : 'no screenshot');
107
+ }
108
+ return r.screenshot;
109
+ }
110
+ /** Stop the running block at its next step. False if nothing was running. */
111
+ async interrupt() {
112
+ const d = await this.http.json('POST', `${this.path}/interrupt`);
113
+ return Boolean(d?.interrupted);
114
+ }
115
+ /** `{ status: open|closed, closedReason?, lastExecAt, ... }`. */
116
+ get() {
117
+ return this.http.json('GET', this.path);
118
+ }
119
+ /** Clear the REPL and release the computer. Safe to call twice. */
120
+ async close() {
121
+ if (this.closed)
122
+ return;
123
+ try {
124
+ await this.http.request('DELETE', this.path);
125
+ }
126
+ catch (err) {
127
+ if (!(err instanceof GoneError))
128
+ throw err;
129
+ }
130
+ this.closed = true;
131
+ }
132
+ }
133
+ function raiseOnBlockError(r) {
134
+ if (r.error)
135
+ throw new BlockError(r.error.kind, r.error.message);
136
+ }
137
+ //# sourceMappingURL=control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * A non-2xx response from the Sai API. `code` is the machine-readable `error`
3
+ * string when the server sent one (`machine_busy`, `link_only`, ...); `message`
4
+ * is the human text; `body` is the parsed JSON body, unchanged.
5
+ */
6
+ export declare class SaiError extends Error {
7
+ readonly status: number;
8
+ readonly code: string | undefined;
9
+ readonly body: Record<string, unknown>;
10
+ readonly retryAfter: number | undefined;
11
+ constructor(message: string, opts?: {
12
+ status?: number;
13
+ code?: string;
14
+ body?: Record<string, unknown>;
15
+ retryAfter?: number;
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ /** The API could not be reached (DNS, TLS, timeout). */
20
+ export declare class ConnectionError extends SaiError {
21
+ }
22
+ /** 400: the request was invalid, e.g. several computers and no `machine`. */
23
+ export declare class BadRequestError extends SaiError {
24
+ }
25
+ /** 401: no key, or the key is unknown or revoked. */
26
+ export declare class AuthenticationError extends SaiError {
27
+ }
28
+ /** 403: the key is valid but the account may not do this (plan, ownership). */
29
+ export declare class PermissionDeniedError extends SaiError {
30
+ }
31
+ /** 404. */
32
+ export declare class NotFoundError extends SaiError {
33
+ }
34
+ /** 409: e.g. `machine_busy`, `link_only`, approval no longer pending. */
35
+ export declare class ConflictError extends SaiError {
36
+ }
37
+ /**
38
+ * 410 `control_closed`: the control lease has ended (closed, sat idle, lost
39
+ * the computer to a Sai task, or the computer stopped answering). `body.reason`
40
+ * says which. Open a new one.
41
+ */
42
+ export declare class GoneError extends SaiError {
43
+ }
44
+ /** 429: a rate limit, or a free-plan budget that resets daily. */
45
+ export declare class RateLimitError extends SaiError {
46
+ }
47
+ /** 503: the computer did not come online, or no capacity. Honor `retryAfter`. */
48
+ export declare class ServiceUnavailableError extends SaiError {
49
+ }
50
+ /**
51
+ * A control helper's Simulang block failed on the computer. `kind` is
52
+ * `exception`, `timeout` or `interrupted`.
53
+ */
54
+ export declare class BlockError extends SaiError {
55
+ readonly kind: string;
56
+ constructor(kind: string, message: string);
57
+ }
58
+ /** The approval must be answered by a human in a browser: open `approvalUrl`. */
59
+ export declare class LinkOnlyApprovalError extends ConflictError {
60
+ get approvalUrl(): string | undefined;
61
+ }
62
+ /**
63
+ * 403 `spend_cap_reached`: the key reached its monthly spend limit, or (on a
64
+ * cloud machine create, `body.scope === 'tenant'`) the Tenant reached its budget. Not
65
+ * retryable: the limit resets at `resetsAt` (ISO 8601, 00:00 UTC on the 1st),
66
+ * or raise it for the key in the portal.
67
+ */
68
+ export declare class SpendCapReachedError extends PermissionDeniedError {
69
+ get resetsAt(): string | undefined;
70
+ }
71
+ export declare function errorFor(status: number, body: Record<string, unknown>, retryAfter: number | undefined): SaiError;
package/dist/errors.js ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * A non-2xx response from the Sai API. `code` is the machine-readable `error`
3
+ * string when the server sent one (`machine_busy`, `link_only`, ...); `message`
4
+ * is the human text; `body` is the parsed JSON body, unchanged.
5
+ */
6
+ export class SaiError extends Error {
7
+ status;
8
+ code;
9
+ body;
10
+ retryAfter;
11
+ constructor(message, opts = {}) {
12
+ super(message, opts.cause === undefined ? undefined : { cause: opts.cause });
13
+ this.name = new.target.name;
14
+ this.status = opts.status ?? 0;
15
+ this.code = opts.code;
16
+ this.body = opts.body ?? {};
17
+ this.retryAfter = opts.retryAfter;
18
+ }
19
+ }
20
+ /** The API could not be reached (DNS, TLS, timeout). */
21
+ export class ConnectionError extends SaiError {
22
+ }
23
+ /** 400: the request was invalid, e.g. several computers and no `machine`. */
24
+ export class BadRequestError extends SaiError {
25
+ }
26
+ /** 401: no key, or the key is unknown or revoked. */
27
+ export class AuthenticationError extends SaiError {
28
+ }
29
+ /** 403: the key is valid but the account may not do this (plan, ownership). */
30
+ export class PermissionDeniedError extends SaiError {
31
+ }
32
+ /** 404. */
33
+ export class NotFoundError extends SaiError {
34
+ }
35
+ /** 409: e.g. `machine_busy`, `link_only`, approval no longer pending. */
36
+ export class ConflictError extends SaiError {
37
+ }
38
+ /**
39
+ * 410 `control_closed`: the control lease has ended (closed, sat idle, lost
40
+ * the computer to a Sai task, or the computer stopped answering). `body.reason`
41
+ * says which. Open a new one.
42
+ */
43
+ export class GoneError extends SaiError {
44
+ }
45
+ /** 429: a rate limit, or a free-plan budget that resets daily. */
46
+ export class RateLimitError extends SaiError {
47
+ }
48
+ /** 503: the computer did not come online, or no capacity. Honor `retryAfter`. */
49
+ export class ServiceUnavailableError extends SaiError {
50
+ }
51
+ /**
52
+ * A control helper's Simulang block failed on the computer. `kind` is
53
+ * `exception`, `timeout` or `interrupted`.
54
+ */
55
+ export class BlockError extends SaiError {
56
+ kind;
57
+ constructor(kind, message) {
58
+ super(`${kind}: ${message}`, { code: kind });
59
+ this.kind = kind;
60
+ }
61
+ }
62
+ /** The approval must be answered by a human in a browser: open `approvalUrl`. */
63
+ export class LinkOnlyApprovalError extends ConflictError {
64
+ get approvalUrl() {
65
+ const url = this.body.approvalUrl;
66
+ return typeof url === 'string' ? url : undefined;
67
+ }
68
+ }
69
+ /**
70
+ * 403 `spend_cap_reached`: the key reached its monthly spend limit, or (on a
71
+ * cloud machine create, `body.scope === 'tenant'`) the Tenant reached its budget. Not
72
+ * retryable: the limit resets at `resetsAt` (ISO 8601, 00:00 UTC on the 1st),
73
+ * or raise it for the key in the portal.
74
+ */
75
+ export class SpendCapReachedError extends PermissionDeniedError {
76
+ get resetsAt() {
77
+ const at = this.body.resetsAt;
78
+ return typeof at === 'string' ? at : undefined;
79
+ }
80
+ }
81
+ const BY_CODE = {
82
+ link_only: LinkOnlyApprovalError,
83
+ spend_cap_reached: SpendCapReachedError,
84
+ };
85
+ const BY_STATUS = {
86
+ 400: BadRequestError,
87
+ 401: AuthenticationError,
88
+ 403: PermissionDeniedError,
89
+ 404: NotFoundError,
90
+ 409: ConflictError,
91
+ 410: GoneError,
92
+ 429: RateLimitError,
93
+ 503: ServiceUnavailableError,
94
+ };
95
+ export function errorFor(status, body, retryAfter) {
96
+ const err = body.error;
97
+ const detail = body.message;
98
+ // Two body shapes: `{ error: "<human text>" }` (/v1/agents) and
99
+ // `{ error: "<code>", message: "<human text>" }` (/v1/machines/{id}/control, newer errors).
100
+ const code = typeof err === 'string' && (detail !== undefined || looksLikeCode(err)) ? err : undefined;
101
+ let message = typeof detail === 'string' ? detail : typeof err === 'string' ? err : `HTTP ${status}`;
102
+ if (status === 401)
103
+ message += ' (SAI_API_KEY was rejected: it may be revoked.)';
104
+ const Cls = (code !== undefined && Object.hasOwn(BY_CODE, code) ? BY_CODE[code] : undefined) ??
105
+ BY_STATUS[status] ??
106
+ SaiError;
107
+ // The `Retry-After` header wins; `retryAfterSeconds` is the same value in the body (`rate_limited`).
108
+ const wait = retryAfter ?? (typeof body.retryAfterSeconds === 'number' ? body.retryAfterSeconds : undefined);
109
+ return new Cls(message, { status, code, body, retryAfter: wait });
110
+ }
111
+ function looksLikeCode(s) {
112
+ return s.length > 0 && !s.includes(' ') && s === s.toLowerCase();
113
+ }
114
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export declare const DEFAULT_BASE_URL = "https://api.simular.ai";
2
+ export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
3
+ /** The bearer token, or a function that returns it before each request. */
4
+ export type Credential = string | (() => Promise<string>);
5
+ export interface RequestOptions {
6
+ json?: unknown;
7
+ params?: Record<string, string | number | undefined>;
8
+ body?: BodyInit;
9
+ headers?: Record<string, string>;
10
+ timeoutMs?: number;
11
+ }
12
+ /** The one place requests are made: auth header, error mapping, timeouts. */
13
+ export declare class Http {
14
+ private readonly credential;
15
+ private readonly timeoutMs;
16
+ private readonly fetchImpl;
17
+ private readonly baseUrl;
18
+ private readonly headers;
19
+ constructor(credential: Credential, baseUrl: string, timeoutMs: number, versionTag: string | undefined, fetchImpl: FetchLike);
20
+ request(method: string, path: string, opts?: RequestOptions): Promise<Response>;
21
+ json<T>(method: string, path: string, opts?: RequestOptions): Promise<T>;
22
+ }
package/dist/http.js ADDED
@@ -0,0 +1,83 @@
1
+ import { ConnectionError, errorFor } from './errors.js';
2
+ import { VERSION } from './version.js';
3
+ export const DEFAULT_BASE_URL = 'https://api.simular.ai';
4
+ /** The one place requests are made: auth header, error mapping, timeouts. */
5
+ export class Http {
6
+ credential;
7
+ timeoutMs;
8
+ fetchImpl;
9
+ baseUrl;
10
+ headers;
11
+ constructor(credential, baseUrl, timeoutMs, versionTag, fetchImpl) {
12
+ this.credential = credential;
13
+ this.timeoutMs = timeoutMs;
14
+ this.fetchImpl = fetchImpl;
15
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
16
+ this.headers = { 'User-Agent': `sai-typescript/${VERSION}` };
17
+ if (typeof credential === 'string')
18
+ this.headers.Authorization = `Bearer ${credential}`;
19
+ // routes the request to a tagged API revision
20
+ if (versionTag)
21
+ this.headers['x-sai-version'] = versionTag;
22
+ }
23
+ async request(method, path, opts = {}) {
24
+ const url = new URL(this.baseUrl + path);
25
+ for (const [k, v] of Object.entries(opts.params ?? {})) {
26
+ if (v !== undefined)
27
+ url.searchParams.set(k, String(v));
28
+ }
29
+ const headers = { ...this.headers, ...opts.headers };
30
+ if (typeof this.credential === 'function') {
31
+ headers.Authorization = `Bearer ${await this.credential()}`;
32
+ }
33
+ let body = opts.body;
34
+ if (opts.json !== undefined) {
35
+ headers['Content-Type'] = 'application/json';
36
+ body = JSON.stringify(opts.json);
37
+ }
38
+ let res;
39
+ try {
40
+ res = await this.fetchImpl(url.toString(), {
41
+ method,
42
+ headers,
43
+ body,
44
+ signal: AbortSignal.timeout(opts.timeoutMs ?? this.timeoutMs),
45
+ });
46
+ }
47
+ catch (err) {
48
+ const name = err instanceof Error ? err.name : '';
49
+ if (name === 'TimeoutError' || name === 'AbortError') {
50
+ throw new ConnectionError(`Request to ${url.host} timed out.`, { cause: err });
51
+ }
52
+ const cause = err instanceof Error ? err.cause : undefined;
53
+ const detail = cause?.message ?? (err instanceof Error ? err.message : String(err));
54
+ throw new ConnectionError(`Could not reach the Sai API at ${url.host}: ${detail}. Check the network and SAI_API_URL.`, { cause: err });
55
+ }
56
+ if (res.status >= 400)
57
+ throw await toError(res);
58
+ return res;
59
+ }
60
+ async json(method, path, opts = {}) {
61
+ const res = await this.request(method, path, opts);
62
+ const text = await res.text();
63
+ return (text ? JSON.parse(text) : null);
64
+ }
65
+ }
66
+ async function toError(res) {
67
+ const text = await res.text().catch(() => '');
68
+ let body;
69
+ try {
70
+ const parsed = JSON.parse(text);
71
+ body =
72
+ parsed && typeof parsed === 'object' && !Array.isArray(parsed)
73
+ ? parsed
74
+ : { error: String(parsed) };
75
+ }
76
+ catch {
77
+ body = { error: text.slice(0, 500) || res.statusText };
78
+ }
79
+ const raw = res.headers.get('retry-after');
80
+ const retryAfter = raw !== null && raw !== '' && !Number.isNaN(Number(raw)) ? Number(raw) : undefined;
81
+ return errorFor(res.status, body, retryAfter);
82
+ }
83
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * TypeScript SDK for the Sai API.
3
+ *
4
+ * - `sai.sessions`: give Sai a task on a computer and get the answer back.
5
+ * - `sai.learn`, `sai.judge`: turn recorded turns or a task into Simulang code, repair it, run
6
+ * judge and repair it on a machine (policy iteration), judge turns.
7
+ * - `sai.control`: drive a cloud computer yourself with Simulang.
8
+ * - `sai.machines`, `sai.models`, `sai.files`, `sai.account`.
9
+ * - `sai.tenants`, `sai.tenantMachines`: your customers under an Organisation (an Organisation Key).
10
+ */
11
+ export { Sai, type SaiOptions } from './client.js';
12
+ export { AuthenticationError, BadRequestError, BlockError, ConflictError, ConnectionError, GoneError, LinkOnlyApprovalError, NotFoundError, PermissionDeniedError, RateLimitError, SaiError, ServiceUnavailableError, SpendCapReachedError, } from './errors.js';
13
+ export { ControlLease } from './control.js';
14
+ export type { MachineRef } from './machines.js';
15
+ export type { TenantMachineRef, TenantRef } from './tenants.js';
16
+ export type { TurnRef } from './turns.js';
17
+ export type { JudgeOptions, LearnOptions } from './learn.js';
18
+ export { Session, Turn, type ApprovalAnswer, type ApprovalHandler, type SendOptions, type WaitOptions, } from './sessions.js';
19
+ export { EVENT_KINDS, TURN_RECORD_STATUSES, TURN_STATUSES, type Account, type Approval, type Attachment, type Check, type CriterionResult, type Enrollment, type Evaluation, type Event, type Evidence, type EventKind, type ExecError, type ExecResult, type Judgement, type LearnIteration, type LearnParameter, type LearnReset, type LearnResult, type LearnRollout, type LearnRun, type LearnTestResult, type LiveView, type Machine, type Model, type Tenant, type TenantMachine, type TenantPage, type TenantToken, type TrajectoryStep, type TurnRecord, type TurnRecordStatus, type TurnResult, type TurnStatus, type Usage, } from './types.js';
20
+ export { VERSION } from './version.js';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * TypeScript SDK for the Sai API.
3
+ *
4
+ * - `sai.sessions`: give Sai a task on a computer and get the answer back.
5
+ * - `sai.learn`, `sai.judge`: turn recorded turns or a task into Simulang code, repair it, run
6
+ * judge and repair it on a machine (policy iteration), judge turns.
7
+ * - `sai.control`: drive a cloud computer yourself with Simulang.
8
+ * - `sai.machines`, `sai.models`, `sai.files`, `sai.account`.
9
+ * - `sai.tenants`, `sai.tenantMachines`: your customers under an Organisation (an Organisation Key).
10
+ */
11
+ export { Sai } from './client.js';
12
+ export { AuthenticationError, BadRequestError, BlockError, ConflictError, ConnectionError, GoneError, LinkOnlyApprovalError, NotFoundError, PermissionDeniedError, RateLimitError, SaiError, ServiceUnavailableError, SpendCapReachedError, } from './errors.js';
13
+ export { ControlLease } from './control.js';
14
+ export { Session, Turn, } from './sessions.js';
15
+ export { EVENT_KINDS, TURN_RECORD_STATUSES, TURN_STATUSES, } from './types.js';
16
+ export { VERSION } from './version.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,GAAG,EAAmB,MAAM,aAAa,CAAA;AAClD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,EACT,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAK3C,OAAO,EACL,OAAO,EACP,IAAI,GAKL,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,aAAa,GAkCd,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Learn and judge (research preview): turn recorded turns, or a task the agent does first, into
3
+ * Simulang code you own; repair that code; run, judge and repair it on a machine until it passes
4
+ * (policy iteration); and judge turns against criteria you choose now.
5
+ *
6
+ * Maps to `/v1/agents/learn` and `/v1/agents/judge`.
7
+ */
8
+ import type { Http } from './http.js';
9
+ import { type MachineRef } from './machines.js';
10
+ import type { TurnRef } from './turns.js';
11
+ import { type LearnRun, type Check, type Evaluation, type Judgement, type LearnResult } from './types.js';
12
+ export interface LearnOptions {
13
+ /**
14
+ * The task, with `{{name}}` placeholders: `'Submit claim for {{patient}} to {{payer}}'`. Without
15
+ * `turns`, the agent does this task first. With `turns`, it defaults to the first turn's.
16
+ */
17
+ taskTemplate?: string;
18
+ /** @deprecated Use `taskTemplate`. */
19
+ template?: string;
20
+ /** A value for every placeholder; with `turns`, defaults to the first turn's. */
21
+ inputs?: Record<string, string | number | boolean>;
22
+ /** Code to repair (with `maxIterations` 0), or to start the run-judge-repair loop from. */
23
+ initialCode?: string;
24
+ /** How `initialCode` did on runs (a repair only). */
25
+ evaluations?: Evaluation[];
26
+ /** What you know about the task, for writing and repairing the code, e.g. "the Save button is under the ⋯ menu". */
27
+ guidance?: string;
28
+ /** @deprecated Use `guidance`. */
29
+ feedback?: string;
30
+ /** For a repair: what earlier versions of the code changed and how they failed, so the repair does not repeat them. */
31
+ history?: string;
32
+ /**
33
+ * For a conversion: the code will be run again and again with no reset in between, so it opens
34
+ * the app or URL itself instead of assuming the screen it starts on.
35
+ */
36
+ runsWithoutReset?: boolean;
37
+ /**
38
+ * Code versions to run, judge and repair: 0 (the default) only writes the code; 3 allows up to
39
+ * two repairs. At most 5.
40
+ */
41
+ maxIterations?: number;
42
+ /** Runs per code version; a version passes when all of them pass. Default 3, at most 5. */
43
+ rollouts?: number;
44
+ /** The machine to run on; optional with one machine. */
45
+ machine?: MachineRef;
46
+ /** What "done" means for the judge; default: the task as written, with its inputs. */
47
+ criteria?: string | Check[];
48
+ /** Run before the agent run and before every run of the code: Simulang `code`, or a `task` for the agent. */
49
+ reset?: {
50
+ code: string;
51
+ } | {
52
+ task: string;
53
+ };
54
+ /** Judge the agent run first; if it fails, the job stops with the judgement and writes no code. */
55
+ judgeInitialAgentRun?: boolean;
56
+ /** After a failed run, let the agent finish the task; its turn feeds the repair. */
57
+ continueWithAgent?: boolean;
58
+ /** Limit of each run of the code, in minutes. Default 15. */
59
+ rolloutMinutes?: number;
60
+ /** Limit of the agent run and of each reset task, in minutes. Default 15. */
61
+ agentRunMinutes?: number;
62
+ /** Limit of each continuation, in minutes. Default 15. */
63
+ continuationMinutes?: number;
64
+ /** Limit of the whole job, in minutes. Default 615, at most 690. */
65
+ maxJobMinutes?: number;
66
+ /** A model id from `sai.models.list()`; without it, Sai picks the model. */
67
+ model?: string;
68
+ /** The same key again returns the earlier result and runs nothing. */
69
+ idempotencyKey?: string;
70
+ timeoutMs?: number;
71
+ }
72
+ export declare class Learn {
73
+ private readonly http;
74
+ constructor(http: Http);
75
+ /**
76
+ * Make Simulang code, and optionally run, judge and repair it on a machine.
77
+ *
78
+ * - `create(turns)`: code from recorded turns (ordered, one session, each sent with
79
+ * `recordTrajectory`). Answers with the code; a longer task takes longer.
80
+ * - `create([], { initialCode, guidance | evaluations })`: a repair. Answers with the code.
81
+ * - `create(turns, { maxIterations: 3 })` or `create([], { taskTemplate, inputs, maxIterations: 3 })`:
82
+ * a job on the machine (from `turns`, or after the agent does the task). Answers at once with
83
+ * `status: 'running'`; read it with `wait()`.
84
+ *
85
+ * A result with `validation.errors` comes back `failed`.
86
+ */
87
+ create(turns: TurnRef[], opts?: LearnOptions): Promise<LearnResult>;
88
+ /** A learn call's result, or a job's progress so far. */
89
+ get(learnId: string): Promise<LearnResult>;
90
+ /**
91
+ * Read a learn job until it ends (`succeeded`, `failed` or `stopped`). `timeoutMs` throws a
92
+ * `TimeoutError` (DOMException) with the job still running; it keeps running.
93
+ */
94
+ wait(job: LearnResult | string, opts?: {
95
+ timeoutMs?: number;
96
+ pollMs?: number;
97
+ }): Promise<LearnResult>;
98
+ /**
99
+ * Stop a learn job at once, whatever step it is on. It keeps the last complete results and
100
+ * reads `stopped` / `cancelled` once it has ended, normally within seconds.
101
+ */
102
+ cancel(job: LearnResult | string): Promise<void>;
103
+ /** One run of a learn job's code: what it returned and logged, and its judgement. */
104
+ rollout(job: LearnResult | string, iteration: number, rollout: number): Promise<LearnRun>;
105
+ }
106
+ export interface JudgeOptions {
107
+ /** Default: the first turn's message. */
108
+ task?: string;
109
+ idempotencyKey?: string;
110
+ timeoutMs?: number;
111
+ }
112
+ export declare class Judge {
113
+ private readonly http;
114
+ constructor(http: Http);
115
+ /**
116
+ * Judge recorded `turns` (one session, as one task) against `criteria`: a sentence for a model
117
+ * to judge, or a list of `Check`s. Nothing runs again, and the turns do not change.
118
+ */
119
+ create(turns: TurnRef[], criteria: string | Check[], opts?: JudgeOptions): Promise<Judgement>;
120
+ get(judgementId: string): Promise<Judgement>;
121
+ }