@simular-ai/sai-sdk 0.0.0-stage → 0.1.0-alpha.1
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.
- package/LICENSE +21 -0
- package/README.md +304 -2
- package/dist/client.d.ts +78 -0
- package/dist/client.js +110 -0
- package/dist/client.js.map +1 -0
- package/dist/control.d.ts +74 -0
- package/dist/control.js +137 -0
- package/dist/control.js.map +1 -0
- package/dist/errors.d.ts +70 -0
- package/dist/errors.js +113 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.d.ts +22 -0
- package/dist/http.js +83 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/learn.d.ts +52 -0
- package/dist/learn.js +95 -0
- package/dist/learn.js.map +1 -0
- package/dist/machines.d.ts +15 -0
- package/dist/machines.js +47 -0
- package/dist/machines.js.map +1 -0
- package/dist/sessions.d.ts +152 -0
- package/dist/sessions.js +378 -0
- package/dist/sessions.js.map +1 -0
- package/dist/tenants.d.ts +66 -0
- package/dist/tenants.js +97 -0
- package/dist/tenants.js.map +1 -0
- package/dist/turns.d.ts +32 -0
- package/dist/turns.js +50 -0
- package/dist/turns.js.map +1 -0
- package/dist/types.d.ts +345 -0
- package/dist/types.js +280 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +39 -4
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Http } from './http.js';
|
|
2
|
+
import { type LiveView, type Machine } from './types.js';
|
|
3
|
+
export type MachineRef = Machine | string;
|
|
4
|
+
/** Machines: the computers Sai works on. Cloud computers, or the customer's own PC with the Sai app. */
|
|
5
|
+
export declare class Machines {
|
|
6
|
+
private readonly http;
|
|
7
|
+
constructor(http: Http);
|
|
8
|
+
list(): Promise<Machine[]>;
|
|
9
|
+
get(machineId: string): Promise<Machine>;
|
|
10
|
+
/** A view-only stream of the screen (Apache Guacamole). The machine must be running. */
|
|
11
|
+
live(machine: MachineRef): Promise<LiveView>;
|
|
12
|
+
/** @internal */
|
|
13
|
+
resolveId(machine: MachineRef | undefined): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
export declare function idOf(machine: MachineRef): string;
|
package/dist/machines.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BadRequestError, NotFoundError } from './errors.js';
|
|
2
|
+
import { parseMachine } from './types.js';
|
|
3
|
+
/** Machines: the computers Sai works on. Cloud computers, or the customer's own PC with the Sai app. */
|
|
4
|
+
export class Machines {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
async list() {
|
|
10
|
+
const d = await this.http.json('GET', '/v1/agents/machines');
|
|
11
|
+
return (d.machines ?? []).map(parseMachine);
|
|
12
|
+
}
|
|
13
|
+
async get(machineId) {
|
|
14
|
+
const m = (await this.list()).find((x) => x.id === machineId);
|
|
15
|
+
if (!m)
|
|
16
|
+
throw new NotFoundError(`Machine ${machineId} not found on this account.`, { status: 404 });
|
|
17
|
+
return m;
|
|
18
|
+
}
|
|
19
|
+
/** A view-only stream of the screen (Apache Guacamole). The machine must be running. */
|
|
20
|
+
async live(machine) {
|
|
21
|
+
const id = idOf(machine);
|
|
22
|
+
const d = await this.http.json('POST', `/v1/agents/machines/${encodeURIComponent(id)}/live`);
|
|
23
|
+
return {
|
|
24
|
+
machineId: typeof d.machineId === 'string' ? d.machineId : id,
|
|
25
|
+
websocketUrl: String(d.websocketUrl),
|
|
26
|
+
width: Number(d.width ?? 0),
|
|
27
|
+
height: Number(d.height ?? 0),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** @internal */
|
|
31
|
+
async resolveId(machine) {
|
|
32
|
+
if (machine)
|
|
33
|
+
return idOf(machine);
|
|
34
|
+
const machines = await this.list();
|
|
35
|
+
if (machines.length === 1)
|
|
36
|
+
return machines[0].id;
|
|
37
|
+
if (machines.length === 0) {
|
|
38
|
+
throw new BadRequestError('No computer on this account. Create one in the Sai app or the portal.', { status: 400 });
|
|
39
|
+
}
|
|
40
|
+
const names = machines.map((m) => (m.name ? `${m.id} (${m.name})` : m.id)).join(', ');
|
|
41
|
+
throw new BadRequestError(`Several computers on this account; pass machine. Candidates: ${names}`, { status: 400 });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function idOf(machine) {
|
|
45
|
+
return typeof machine === 'string' ? machine : machine.id;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=machines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machines.js","sourceRoot":"","sources":["../src/machines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5D,OAAO,EAAE,YAAY,EAA+B,MAAM,YAAY,CAAA;AAItE,wGAAwG;AACxG,MAAM,OAAO,QAAQ;IACU;IAA7B,YAA6B,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;IAE3C,KAAK,CAAC,IAAI;QACR,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAC5B,KAAK,EACL,qBAAqB,CACtB,CAAA;QACD,OAAO,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAA;QAC7D,IAAI,CAAC,CAAC;YACJ,MAAM,IAAI,aAAa,CAAC,WAAW,SAAS,6BAA6B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QAC7F,OAAO,CAAC,CAAA;IACV,CAAC;IAED,wFAAwF;IACxF,KAAK,CAAC,IAAI,CAAC,OAAmB;QAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;QACxB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAC5B,MAAM,EACN,uBAAuB,kBAAkB,CAAC,EAAE,CAAC,OAAO,CACrD,CAAA;QACD,OAAO;YACL,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YAC7D,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;YACpC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;SAC9B,CAAA;IACH,CAAC;IAED,gBAAgB;IAChB,KAAK,CAAC,SAAS,CAAC,OAA+B;QAC7C,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAA;QACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAClC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC,CAAC,CAAE,CAAC,EAAE,CAAA;QACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,eAAe,CACvB,uEAAuE,EACvE,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;QACH,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrF,MAAM,IAAI,eAAe,CACvB,gEAAgE,KAAK,EAAE,EACvE,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;IACH,CAAC;CACF;AAED,MAAM,UAAU,IAAI,CAAC,OAAmB;IACtC,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAA;AAC3D,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions: a conversation with Sai on one computer. Sai decides every click.
|
|
3
|
+
*
|
|
4
|
+
* Maps to `/v1/agents/*`: `new-session`, `message` (wait=false), `events`,
|
|
5
|
+
* `approve`, `abort`. Every message gets a turn id (`turn.id`, read with
|
|
6
|
+
* `sai.turns`); a message with `inputs`, `outputSchema` or `successCriteria`
|
|
7
|
+
* is structured and its turn also returns a typed result.
|
|
8
|
+
*/
|
|
9
|
+
import type { Http } from './http.js';
|
|
10
|
+
import { type MachineRef, type Machines } from './machines.js';
|
|
11
|
+
import { type Approval, type Attachment, type Check, type Event, type TurnRecord, type TurnRecordStatus, type TurnResult, type TurnStatus } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* What an `onApproval` handler answers: a response (`yes`, `no`, `task`), a
|
|
14
|
+
* `[response, selections]` pair for a choice, or null to leave the approval
|
|
15
|
+
* pending (e.g. a human answers it in a browser).
|
|
16
|
+
*/
|
|
17
|
+
export type ApprovalAnswer = string | [string, string[][]] | null;
|
|
18
|
+
export type ApprovalHandler = (approval: Approval) => ApprovalAnswer | Promise<ApprovalAnswer>;
|
|
19
|
+
export interface SendOptions {
|
|
20
|
+
/** An id from `sai.models.list()` (or `auto`); sticks to the session until changed. */
|
|
21
|
+
model?: string;
|
|
22
|
+
attachments?: Attachment[];
|
|
23
|
+
/** Values for the `{{name}}` placeholders in the message. Makes the message structured. */
|
|
24
|
+
inputs?: Record<string, string | number | boolean>;
|
|
25
|
+
/** JSON Schema (at most 32 KB) the turn's output must match. Makes the message structured. */
|
|
26
|
+
outputSchema?: Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* A guideline for a judge, or yes/no checks, the turn is checked against.
|
|
29
|
+
* Makes the message structured.
|
|
30
|
+
*/
|
|
31
|
+
successCriteria?: string | Check[];
|
|
32
|
+
/** The same key again returns the earlier turn and sends nothing. */
|
|
33
|
+
idempotencyKey?: string;
|
|
34
|
+
/** Keep a screenshot and the action for each step (`sai.turns.trajectory()`). */
|
|
35
|
+
recordTrajectory?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Run the turn this message starts without approval cards, as if "Trust for
|
|
38
|
+
* this task" had been answered; the grant ends with the turn. A message that
|
|
39
|
+
* steers a running turn changes nothing.
|
|
40
|
+
*/
|
|
41
|
+
autonomous?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface WaitOptions {
|
|
44
|
+
onApproval?: ApprovalHandler;
|
|
45
|
+
/** Throws a `TimeoutError` (DOMException) with the turn still running. */
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
/** Seconds the server may hold one poll; it caps at 60. */
|
|
48
|
+
pollWait?: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class Sessions {
|
|
51
|
+
private readonly http;
|
|
52
|
+
private readonly machines;
|
|
53
|
+
constructor(http: Http, machines: Machines);
|
|
54
|
+
/**
|
|
55
|
+
* Start a fresh conversation on a computer: the next message has no memory
|
|
56
|
+
* of earlier ones. `machine` may be omitted with one computer.
|
|
57
|
+
*/
|
|
58
|
+
create(opts?: {
|
|
59
|
+
machine?: MachineRef;
|
|
60
|
+
}): Promise<Session>;
|
|
61
|
+
/** Reattach to a session started elsewhere, e.g. to poll or abort it. */
|
|
62
|
+
resume(sessionId: string, opts?: {
|
|
63
|
+
machine?: MachineRef;
|
|
64
|
+
}): Session;
|
|
65
|
+
}
|
|
66
|
+
/** A conversation with Sai. Each `send()` is a turn; turns share context. */
|
|
67
|
+
export declare class Session {
|
|
68
|
+
private readonly http;
|
|
69
|
+
machineId: string | null;
|
|
70
|
+
id: string | null;
|
|
71
|
+
constructor(http: Http, machineId: string | null, id: string | null);
|
|
72
|
+
/**
|
|
73
|
+
* Give Sai a task, or steer the running one. Returns at once. Sent while a
|
|
74
|
+
* turn is running, the message steers that turn (`turn.queued` is true).
|
|
75
|
+
*
|
|
76
|
+
* Any of `inputs`, `outputSchema` or `successCriteria` makes the message
|
|
77
|
+
* structured: the message is a template whose `{{name}}` placeholders are
|
|
78
|
+
* filled from `inputs`, the output must match `outputSchema`, and the turn
|
|
79
|
+
* is checked against `successCriteria`. `wait()` then also returns the
|
|
80
|
+
* turn's record in `result.record`. A structured message is refused with
|
|
81
|
+
* `ConflictError` (`session_busy`) while a turn is running. These go to the
|
|
82
|
+
* API as `options`.
|
|
83
|
+
*/
|
|
84
|
+
send(message: string, opts?: SendOptions): Promise<Turn>;
|
|
85
|
+
/** `send()` then `wait()`: the answer, or where it stopped. */
|
|
86
|
+
run(message: string, opts?: SendOptions & WaitOptions): Promise<TurnResult>;
|
|
87
|
+
/** Stop the running turn. Pending approvals are denied. False if nothing was running. */
|
|
88
|
+
abort(): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Answer an approval: `yes`, `no`, or `task` (allow for the rest of the task).
|
|
91
|
+
* A `choice` approval needs `selections`, one list of option values per
|
|
92
|
+
* question. Throws `LinkOnlyApprovalError` (with `approvalUrl`) when only a
|
|
93
|
+
* browser can answer it. Resolves to `approved`, `approved_task` or `denied`.
|
|
94
|
+
*/
|
|
95
|
+
respond(approval: Approval | string, response?: string, opts?: {
|
|
96
|
+
selections?: string[][];
|
|
97
|
+
}): Promise<string>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* One message's work. Iterate `events()` to watch it, or `wait()` for the
|
|
101
|
+
* result. `id` is the turn the message started, or the running turn it joined
|
|
102
|
+
* (`sai.turns.get(turn)`); null when the message was answered without one.
|
|
103
|
+
*/
|
|
104
|
+
export declare class Turn {
|
|
105
|
+
#private;
|
|
106
|
+
readonly session: Session;
|
|
107
|
+
private readonly http;
|
|
108
|
+
readonly queued: boolean;
|
|
109
|
+
readonly id: string | null;
|
|
110
|
+
private cursor;
|
|
111
|
+
private last;
|
|
112
|
+
private readonly structured;
|
|
113
|
+
private readonly replay;
|
|
114
|
+
private readonly local;
|
|
115
|
+
constructor(session: Session, http: Http, queued: boolean, done?: TurnResult | null, turn?: {
|
|
116
|
+
id: string | null;
|
|
117
|
+
structured: boolean;
|
|
118
|
+
replay?: TurnRecord;
|
|
119
|
+
});
|
|
120
|
+
get status(): TurnStatus;
|
|
121
|
+
/** The last known state, or null before the first poll. */
|
|
122
|
+
get result(): TurnResult | null;
|
|
123
|
+
/**
|
|
124
|
+
* Yield events until the turn is idle or errors. It keeps going through
|
|
125
|
+
* `needs_approval`: answer with `turn.respond(ev.approval, ...)` inside the
|
|
126
|
+
* loop, or let a human answer a link-only approval in a browser. Without
|
|
127
|
+
* `raw`, framing, reasoning and tool-call frames are skipped.
|
|
128
|
+
*/
|
|
129
|
+
events(opts?: {
|
|
130
|
+
raw?: boolean;
|
|
131
|
+
pollWait?: number;
|
|
132
|
+
}): AsyncGenerator<Event>;
|
|
133
|
+
/**
|
|
134
|
+
* Wait until the turn is done, or stops on an approval nobody answered.
|
|
135
|
+
* Without `onApproval`, resolves with `status === 'needs_approval'` and the
|
|
136
|
+
* `approval` so the caller can decide. With it, the handler's answer is sent
|
|
137
|
+
* and waiting continues; a handler returning null leaves the approval to
|
|
138
|
+
* someone else (a link-only one to a human) and keeps waiting. For a
|
|
139
|
+
* structured message, it then waits for the turn's record (`result.record`:
|
|
140
|
+
* output, evidence), which is worked out after the turn.
|
|
141
|
+
*/
|
|
142
|
+
wait(opts?: WaitOptions): Promise<TurnResult>;
|
|
143
|
+
respond(approval: Approval | string, response?: string, opts?: {
|
|
144
|
+
selections?: string[][];
|
|
145
|
+
}): Promise<string>;
|
|
146
|
+
abort(): Promise<boolean>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Read the turn's record until its status is in `stop`. Throws a `TimeoutError`
|
|
150
|
+
* (DOMException) past `deadline` (epoch ms).
|
|
151
|
+
*/
|
|
152
|
+
export declare function waitTurnRecord(http: Http, turnId: string, deadline: number | null, stop?: readonly TurnRecordStatus[]): Promise<TurnRecord>;
|
package/dist/sessions.js
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions: a conversation with Sai on one computer. Sai decides every click.
|
|
3
|
+
*
|
|
4
|
+
* Maps to `/v1/agents/*`: `new-session`, `message` (wait=false), `events`,
|
|
5
|
+
* `approve`, `abort`. Every message gets a turn id (`turn.id`, read with
|
|
6
|
+
* `sai.turns`); a message with `inputs`, `outputSchema` or `successCriteria`
|
|
7
|
+
* is structured and its turn also returns a typed result.
|
|
8
|
+
*/
|
|
9
|
+
import { ConflictError, LinkOnlyApprovalError, NotFoundError, RateLimitError } from './errors.js';
|
|
10
|
+
import { idOf } from './machines.js';
|
|
11
|
+
import { parseApproval, parseEvent, parseTurnRecord, parseUsage, } from './types.js';
|
|
12
|
+
const POLL_WAIT = 30;
|
|
13
|
+
/** Between turn reads; `GET /v1/agents/turns/{id}` never holds. */
|
|
14
|
+
const RECORD_POLL_INTERVAL_MS = 2_000;
|
|
15
|
+
export class Sessions {
|
|
16
|
+
http;
|
|
17
|
+
machines;
|
|
18
|
+
constructor(http, machines) {
|
|
19
|
+
this.http = http;
|
|
20
|
+
this.machines = machines;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Start a fresh conversation on a computer: the next message has no memory
|
|
24
|
+
* of earlier ones. `machine` may be omitted with one computer.
|
|
25
|
+
*/
|
|
26
|
+
async create(opts = {}) {
|
|
27
|
+
const machineId = await this.machines.resolveId(opts.machine);
|
|
28
|
+
let sessionId = null;
|
|
29
|
+
try {
|
|
30
|
+
const d = await this.http.json('POST', '/v1/agents/new-session', {
|
|
31
|
+
json: { machineId, channel: 'api' },
|
|
32
|
+
});
|
|
33
|
+
sessionId = d.sessionId ?? null;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
// A free account's computer between claims has no conversation to
|
|
37
|
+
// rotate; the first message starts one.
|
|
38
|
+
if (!(err instanceof NotFoundError))
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
return new Session(this.http, machineId, sessionId);
|
|
42
|
+
}
|
|
43
|
+
/** Reattach to a session started elsewhere, e.g. to poll or abort it. */
|
|
44
|
+
resume(sessionId, opts = {}) {
|
|
45
|
+
return new Session(this.http, opts.machine ? idOf(opts.machine) : null, sessionId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** A conversation with Sai. Each `send()` is a turn; turns share context. */
|
|
49
|
+
export class Session {
|
|
50
|
+
http;
|
|
51
|
+
machineId;
|
|
52
|
+
id;
|
|
53
|
+
constructor(http, machineId, id) {
|
|
54
|
+
this.http = http;
|
|
55
|
+
this.machineId = machineId;
|
|
56
|
+
this.id = id;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Give Sai a task, or steer the running one. Returns at once. Sent while a
|
|
60
|
+
* turn is running, the message steers that turn (`turn.queued` is true).
|
|
61
|
+
*
|
|
62
|
+
* Any of `inputs`, `outputSchema` or `successCriteria` makes the message
|
|
63
|
+
* structured: the message is a template whose `{{name}}` placeholders are
|
|
64
|
+
* filled from `inputs`, the output must match `outputSchema`, and the turn
|
|
65
|
+
* is checked against `successCriteria`. `wait()` then also returns the
|
|
66
|
+
* turn's record in `result.record`. A structured message is refused with
|
|
67
|
+
* `ConflictError` (`session_busy`) while a turn is running. These go to the
|
|
68
|
+
* API as `options`.
|
|
69
|
+
*/
|
|
70
|
+
async send(message, opts = {}) {
|
|
71
|
+
const body = { message, wait: false };
|
|
72
|
+
if (this.machineId)
|
|
73
|
+
body.machineId = this.machineId;
|
|
74
|
+
if (this.id)
|
|
75
|
+
body.sessionId = this.id;
|
|
76
|
+
if (opts.model)
|
|
77
|
+
body.model = opts.model;
|
|
78
|
+
if (opts.attachments?.length)
|
|
79
|
+
body.attachments = opts.attachments.map((a) => a.raw);
|
|
80
|
+
if (opts.autonomous)
|
|
81
|
+
body.autonomous = true;
|
|
82
|
+
const options = {};
|
|
83
|
+
if (opts.inputs !== undefined)
|
|
84
|
+
options.inputs = opts.inputs;
|
|
85
|
+
if (opts.outputSchema !== undefined)
|
|
86
|
+
options.output_schema = opts.outputSchema;
|
|
87
|
+
if (opts.successCriteria !== undefined)
|
|
88
|
+
options.success_criteria = opts.successCriteria;
|
|
89
|
+
if (opts.idempotencyKey !== undefined)
|
|
90
|
+
options.idempotency_key = opts.idempotencyKey;
|
|
91
|
+
if (opts.recordTrajectory)
|
|
92
|
+
options.recordTrajectory = true;
|
|
93
|
+
if (Object.keys(options).length)
|
|
94
|
+
body.options = options;
|
|
95
|
+
const structured = [opts.inputs, opts.outputSchema, opts.successCriteria].some((v) => v !== undefined);
|
|
96
|
+
const d = await this.http.json('POST', '/v1/agents/message', {
|
|
97
|
+
json: body,
|
|
98
|
+
});
|
|
99
|
+
if (d.idempotent_replay) {
|
|
100
|
+
// The key was used before: this is that turn, and nothing was sent.
|
|
101
|
+
const record = parseTurnRecord(d);
|
|
102
|
+
this.id = record.sessionId ?? this.id;
|
|
103
|
+
this.machineId = record.machineId || this.machineId;
|
|
104
|
+
return new Turn(this, this.http, false, null, { id: record.id, structured, replay: record });
|
|
105
|
+
}
|
|
106
|
+
if (typeof d.sessionId !== 'string' || !d.sessionId) {
|
|
107
|
+
// Handled without starting a task (e.g. a plain acknowledgement): the reply is in `reply`,
|
|
108
|
+
// or in `error` on servers before `reply` existed.
|
|
109
|
+
const text = typeof d.reply === 'string' ? d.reply : typeof d.error === 'string' ? d.error : '';
|
|
110
|
+
return new Turn(this, this.http, false, localResult(this.id ?? '', text));
|
|
111
|
+
}
|
|
112
|
+
this.id = d.sessionId;
|
|
113
|
+
if (typeof d.machineId === 'string')
|
|
114
|
+
this.machineId = d.machineId;
|
|
115
|
+
const id = typeof d.turnId === 'string' ? d.turnId : null;
|
|
116
|
+
return new Turn(this, this.http, Boolean(d.queued), null, { id, structured });
|
|
117
|
+
}
|
|
118
|
+
/** `send()` then `wait()`: the answer, or where it stopped. */
|
|
119
|
+
async run(message, opts = {}) {
|
|
120
|
+
const turn = await this.send(message, opts);
|
|
121
|
+
return turn.wait(opts);
|
|
122
|
+
}
|
|
123
|
+
/** Stop the running turn. Pending approvals are denied. False if nothing was running. */
|
|
124
|
+
async abort() {
|
|
125
|
+
if (!this.id)
|
|
126
|
+
return false;
|
|
127
|
+
const d = await this.http.json('POST', '/v1/agents/abort', {
|
|
128
|
+
json: { sessionId: this.id },
|
|
129
|
+
});
|
|
130
|
+
return Boolean(d.aborted);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Answer an approval: `yes`, `no`, or `task` (allow for the rest of the task).
|
|
134
|
+
* A `choice` approval needs `selections`, one list of option values per
|
|
135
|
+
* question. Throws `LinkOnlyApprovalError` (with `approvalUrl`) when only a
|
|
136
|
+
* browser can answer it. Resolves to `approved`, `approved_task` or `denied`.
|
|
137
|
+
*/
|
|
138
|
+
async respond(approval, response = 'yes', opts = {}) {
|
|
139
|
+
if (typeof approval !== 'string' && approval.isLinkOnly) {
|
|
140
|
+
throw new LinkOnlyApprovalError('This approval must be completed in a browser. Open approval.url.', { status: 409, code: 'link_only', body: { approvalUrl: approval.url } });
|
|
141
|
+
}
|
|
142
|
+
const body = {
|
|
143
|
+
approvalId: typeof approval === 'string' ? approval : approval.id,
|
|
144
|
+
response,
|
|
145
|
+
};
|
|
146
|
+
if (opts.selections)
|
|
147
|
+
body.selections = opts.selections;
|
|
148
|
+
const d = await this.http.json('POST', '/v1/agents/approve', {
|
|
149
|
+
json: body,
|
|
150
|
+
});
|
|
151
|
+
return d.status ?? '';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* One message's work. Iterate `events()` to watch it, or `wait()` for the
|
|
156
|
+
* result. `id` is the turn the message started, or the running turn it joined
|
|
157
|
+
* (`sai.turns.get(turn)`); null when the message was answered without one.
|
|
158
|
+
*/
|
|
159
|
+
export class Turn {
|
|
160
|
+
session;
|
|
161
|
+
http;
|
|
162
|
+
queued;
|
|
163
|
+
id;
|
|
164
|
+
cursor = null;
|
|
165
|
+
last;
|
|
166
|
+
structured;
|
|
167
|
+
replay;
|
|
168
|
+
// answered without starting a task, or an idempotent replay: no events to poll
|
|
169
|
+
local;
|
|
170
|
+
constructor(session, http, queued, done = null, turn = {
|
|
171
|
+
id: null,
|
|
172
|
+
structured: false,
|
|
173
|
+
}) {
|
|
174
|
+
this.session = session;
|
|
175
|
+
this.http = http;
|
|
176
|
+
this.queued = queued;
|
|
177
|
+
this.last = done;
|
|
178
|
+
this.id = turn.id;
|
|
179
|
+
this.structured = turn.structured;
|
|
180
|
+
this.replay = turn.replay ?? null;
|
|
181
|
+
this.local = done !== null || this.replay !== null;
|
|
182
|
+
}
|
|
183
|
+
get status() {
|
|
184
|
+
return this.last?.status ?? 'running';
|
|
185
|
+
}
|
|
186
|
+
/** The last known state, or null before the first poll. */
|
|
187
|
+
get result() {
|
|
188
|
+
return this.last;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Yield events until the turn is idle or errors. It keeps going through
|
|
192
|
+
* `needs_approval`: answer with `turn.respond(ev.approval, ...)` inside the
|
|
193
|
+
* loop, or let a human answer a link-only approval in a browser. Without
|
|
194
|
+
* `raw`, framing, reasoning and tool-call frames are skipped.
|
|
195
|
+
*/
|
|
196
|
+
async *events(opts = {}) {
|
|
197
|
+
if (this.local)
|
|
198
|
+
return;
|
|
199
|
+
for (;;) {
|
|
200
|
+
const page = await this.#poll(opts.pollWait ?? POLL_WAIT);
|
|
201
|
+
for (const e of page.events ?? []) {
|
|
202
|
+
const ev = parseEvent(e);
|
|
203
|
+
if (opts.raw || ev.kind !== 'other')
|
|
204
|
+
yield ev;
|
|
205
|
+
}
|
|
206
|
+
if (page.status === 'idle' || page.status === 'error')
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Wait until the turn is done, or stops on an approval nobody answered.
|
|
212
|
+
* Without `onApproval`, resolves with `status === 'needs_approval'` and the
|
|
213
|
+
* `approval` so the caller can decide. With it, the handler's answer is sent
|
|
214
|
+
* and waiting continues; a handler returning null leaves the approval to
|
|
215
|
+
* someone else (a link-only one to a human) and keeps waiting. For a
|
|
216
|
+
* structured message, it then waits for the turn's record (`result.record`:
|
|
217
|
+
* output, evidence), which is worked out after the turn.
|
|
218
|
+
*/
|
|
219
|
+
async wait(opts = {}) {
|
|
220
|
+
const deadline = opts.timeoutMs === undefined ? null : Date.now() + opts.timeoutMs;
|
|
221
|
+
if (this.replay) {
|
|
222
|
+
const record = this.replay.done
|
|
223
|
+
? this.replay
|
|
224
|
+
: await waitTurnRecord(this.http, this.replay.id, deadline);
|
|
225
|
+
this.last = replayResult(record, record.sessionId ?? this.session.id ?? '');
|
|
226
|
+
return this.last;
|
|
227
|
+
}
|
|
228
|
+
if (this.local)
|
|
229
|
+
return this.last;
|
|
230
|
+
const answered = new Set();
|
|
231
|
+
for (;;) {
|
|
232
|
+
let pollWait = opts.pollWait ?? POLL_WAIT;
|
|
233
|
+
if (deadline !== null) {
|
|
234
|
+
const left = deadline - Date.now();
|
|
235
|
+
if (left <= 0) {
|
|
236
|
+
throw new DOMException(`Turn still ${this.status} after ${opts.timeoutMs}ms (session ${this.session.id}).`, 'TimeoutError');
|
|
237
|
+
}
|
|
238
|
+
pollWait = Math.max(1, Math.min(pollWait, Math.floor(left / 1000)));
|
|
239
|
+
}
|
|
240
|
+
const page = await this.#poll(pollWait);
|
|
241
|
+
if (page.status === 'idle' || page.status === 'error') {
|
|
242
|
+
if (this.structured && this.id) {
|
|
243
|
+
this.last = withRecord(this.last, await waitTurnRecord(this.http, this.id, deadline));
|
|
244
|
+
}
|
|
245
|
+
return this.last;
|
|
246
|
+
}
|
|
247
|
+
const approval = this.last?.approval;
|
|
248
|
+
if (page.status !== 'needs_approval' || !approval)
|
|
249
|
+
continue;
|
|
250
|
+
if (!opts.onApproval)
|
|
251
|
+
return this.last;
|
|
252
|
+
if (answered.has(approval.id))
|
|
253
|
+
continue;
|
|
254
|
+
const answer = await opts.onApproval(approval);
|
|
255
|
+
answered.add(approval.id);
|
|
256
|
+
if (answer === null)
|
|
257
|
+
continue;
|
|
258
|
+
const [response, selections] = typeof answer === 'string' ? [answer, undefined] : answer;
|
|
259
|
+
try {
|
|
260
|
+
await this.session.respond(approval, response, { selections });
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
// answered elsewhere or expired; the next poll shows the new state
|
|
264
|
+
if (!(err instanceof ConflictError))
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
respond(approval, response = 'yes', opts = {}) {
|
|
270
|
+
return this.session.respond(approval, response, opts);
|
|
271
|
+
}
|
|
272
|
+
abort() {
|
|
273
|
+
return this.session.abort();
|
|
274
|
+
}
|
|
275
|
+
async #poll(wait) {
|
|
276
|
+
let page;
|
|
277
|
+
for (;;) {
|
|
278
|
+
try {
|
|
279
|
+
page = await this.http.json('GET', '/v1/agents/events', {
|
|
280
|
+
params: { sessionId: this.session.id ?? '', wait, since: this.cursor ?? undefined },
|
|
281
|
+
timeoutMs: (wait + 30) * 1000,
|
|
282
|
+
});
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (!(err instanceof RateLimitError))
|
|
287
|
+
throw err;
|
|
288
|
+
await new Promise((r) => setTimeout(r, (err.retryAfter ?? 30) * 1000));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.cursor = page.cursor ?? this.cursor;
|
|
292
|
+
let error = this.last?.error ?? null;
|
|
293
|
+
let errorCode = this.last?.errorCode ?? null;
|
|
294
|
+
for (const e of page.events ?? []) {
|
|
295
|
+
if (e.type === 'error') {
|
|
296
|
+
error = typeof e.errorText === 'string' ? e.errorText : error;
|
|
297
|
+
errorCode = typeof e.code === 'string' ? e.code : errorCode;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const status = page.status ?? 'running';
|
|
301
|
+
this.last = {
|
|
302
|
+
status,
|
|
303
|
+
text: page.text ?? '',
|
|
304
|
+
sessionId: page.sessionId ?? this.session.id ?? '',
|
|
305
|
+
approval: page.approval ? parseApproval(page.approval) : null,
|
|
306
|
+
error,
|
|
307
|
+
errorCode,
|
|
308
|
+
usage: parseUsage(page.usage),
|
|
309
|
+
sessionUsage: parseUsage(page.sessionUsage),
|
|
310
|
+
record: null,
|
|
311
|
+
ok: status === 'idle',
|
|
312
|
+
};
|
|
313
|
+
return page;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Read the turn's record until its status is in `stop`. Throws a `TimeoutError`
|
|
318
|
+
* (DOMException) past `deadline` (epoch ms).
|
|
319
|
+
*/
|
|
320
|
+
export async function waitTurnRecord(http, turnId, deadline, stop = ['succeeded', 'failed']) {
|
|
321
|
+
for (;;) {
|
|
322
|
+
let record;
|
|
323
|
+
try {
|
|
324
|
+
record = parseTurnRecord(await http.json('GET', `/v1/agents/turns/${encodeURIComponent(turnId)}`));
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
if (!(err instanceof RateLimitError))
|
|
328
|
+
throw err;
|
|
329
|
+
await sleep((err.retryAfter ?? 30) * 1000);
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (stop.includes(record.status))
|
|
333
|
+
return record;
|
|
334
|
+
if (deadline !== null && Date.now() + RECORD_POLL_INTERVAL_MS > deadline) {
|
|
335
|
+
throw new DOMException(`Turn ${turnId} still ${record.status}.`, 'TimeoutError');
|
|
336
|
+
}
|
|
337
|
+
await sleep(RECORD_POLL_INTERVAL_MS);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
341
|
+
function withRecord(result, record) {
|
|
342
|
+
return { ...result, record, ok: result.status === 'idle' && record.ok };
|
|
343
|
+
}
|
|
344
|
+
// A turn that failed for these reasons still has the agent's answer; the turn itself did not break.
|
|
345
|
+
const ANSWERED_REASONS = ['output_invalid', 'criteria_not_met', 'criteria_unchecked'];
|
|
346
|
+
/** The result the live path would have returned for this finished turn, from its record. */
|
|
347
|
+
function replayResult(record, sessionId) {
|
|
348
|
+
const result = localResult(sessionId, record.rawAnswer || outputText(record.output));
|
|
349
|
+
if (record.status === 'failed' && !ANSWERED_REASONS.includes(record.reasonCode ?? '')) {
|
|
350
|
+
result.status = 'error';
|
|
351
|
+
result.text = '';
|
|
352
|
+
result.error = record.rawAnswer || `The turn failed (${record.reasonCode ?? 'unknown'}).`;
|
|
353
|
+
result.errorCode = record.errorCode;
|
|
354
|
+
}
|
|
355
|
+
result.usage = record.usage;
|
|
356
|
+
return withRecord(result, record);
|
|
357
|
+
}
|
|
358
|
+
/** `output` as text: a plain message's answer as is, an `outputSchema` object as JSON. */
|
|
359
|
+
function outputText(output) {
|
|
360
|
+
if (output === null || output === undefined)
|
|
361
|
+
return '';
|
|
362
|
+
return typeof output === 'string' ? output : JSON.stringify(output);
|
|
363
|
+
}
|
|
364
|
+
function localResult(sessionId, text) {
|
|
365
|
+
return {
|
|
366
|
+
status: 'idle',
|
|
367
|
+
text,
|
|
368
|
+
sessionId,
|
|
369
|
+
approval: null,
|
|
370
|
+
error: null,
|
|
371
|
+
errorCode: null,
|
|
372
|
+
usage: null,
|
|
373
|
+
sessionUsage: null,
|
|
374
|
+
record: null,
|
|
375
|
+
ok: true,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
|