@isomorph.ai/app-sdk 1.36.3 → 1.37.0
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/README.md +3 -2
- package/dist/computer-use.d.ts +13 -0
- package/dist/computer-use.js +14 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -393,7 +393,7 @@ A job's agent can hand one browser task, writes included, to the computer use se
|
|
|
393
393
|
import { createComputerUseTool } from '@isomorph.ai/app-sdk/dist/computer-use.js';
|
|
394
394
|
// Inside a job handler:
|
|
395
395
|
const computerUse = createComputerUseTool({ runKey: ctx.runId ?? `my-job/${ctx.scheduledAt}`, progress: ctx.progress, cancelled: ctx.cancelled });
|
|
396
|
-
// Add { computerUse } to generateText's tools. It returns { status: 'done' | 'failed', summary, finalUrl }.
|
|
396
|
+
// Add { computerUse } to generateText's tools. It returns { status: 'done' | 'failed', summary, finalUrl, downloads }.
|
|
397
397
|
```
|
|
398
398
|
|
|
399
399
|
- The tool calls the task API at `ISOMORPH_COMPUTER_USE_URL` (region `ISOMORPH_COMPUTER_USE_REGION`, default `us-east-1`); Provision sets both when the cell has the API. Each request is signed with SigV4 (`execute-api`) as the runtime's own role: the Lambda environment's credentials, or on a cluster pod its ServiceAccount role through STS `AssumeRoleWithWebIdentity`.
|
|
@@ -409,10 +409,11 @@ Options the app passes, never the model:
|
|
|
409
409
|
- `session`: the name of a runtime secret a sign-in was saved under (`finishSignIn`'s `saveAs`, below). The task starts signed in and can use only that sign-in's websites. When the task is `done` the refreshed session is saved back to the same secret. A missing one fails with `No saved sign-in named <name>.` Run one task per saved sign-in at a time: two tasks would both save back, and some websites sign out the older copy.
|
|
410
410
|
- `secrets`: `{ name: value }`, at most 10, names `^[A-Za-z][A-Za-z0-9_-]{0,63}$`, values up to 4096 bytes. The computer types a value into a password field by its name; the model sees only the names. Never put a password or any other credential in the task text; pass it here and say "sign in with the `password` secret".
|
|
411
411
|
- `allowedHosts`: the websites (1 to 10 lower-case hostnames) a task with `secrets` and no `session` may use. A saved sign-in carries its own.
|
|
412
|
+
- `onDownload({ name, contentType, size, blob })`: called once for each file a `done` task downloaded, one at a time, before the tool returns (at most 10 files, 100 MiB each). Store the `blob` yourself; the CUA keeps the files for a day at most. Without it nothing is fetched. A link that does not answer 200 fails the tool. The model only sees `downloads: [{ name, size }]`.
|
|
412
413
|
|
|
413
414
|
A task with `session` or `secrets` works the page through clicks and typing only. `connectionId` is gone: pass `session`.
|
|
414
415
|
|
|
415
|
-
(1.25.0, 1.36.0; data plane ADR 0078, ADR 0090)
|
|
416
|
+
(1.25.0, 1.36.0, 1.37.0; data plane ADR 0078, ADR 0090, ADR 0091)
|
|
416
417
|
|
|
417
418
|
## Browser sign-in for computer use
|
|
418
419
|
|
package/dist/computer-use.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ export interface ComputerUseFile {
|
|
|
3
3
|
contentType: "application/pdf";
|
|
4
4
|
dataBase64: string;
|
|
5
5
|
}
|
|
6
|
+
export interface ComputerUseDownload {
|
|
7
|
+
name: string;
|
|
8
|
+
contentType: string;
|
|
9
|
+
size: number;
|
|
10
|
+
blob: Blob;
|
|
11
|
+
}
|
|
6
12
|
export interface ComputerUseOptions {
|
|
7
13
|
/** App-authorized PDFs, at most five files and 2 MiB total. Never supplied by the model. */
|
|
8
14
|
files?: readonly ComputerUseFile[];
|
|
@@ -18,6 +24,8 @@ export interface ComputerUseOptions {
|
|
|
18
24
|
* Never put a credential in the task text.
|
|
19
25
|
*/
|
|
20
26
|
secrets?: Readonly<Record<string, string>>;
|
|
27
|
+
/** The app's code gets each file the task downloaded, one at a time, when the task is done. Never seen by the model. */
|
|
28
|
+
onDownload?(download: ComputerUseDownload): Promise<void> | void;
|
|
21
29
|
/** The job's runId, or `<job name>/<scheduledAt>` for a scheduled job: one task record per job run. */
|
|
22
30
|
runKey: string;
|
|
23
31
|
/** The job's progress: called on each new step and at least once a minute, which renews the job's lease. */
|
|
@@ -35,6 +43,11 @@ export interface ComputerUseResult {
|
|
|
35
43
|
summary: string | null;
|
|
36
44
|
/** The page the browser was on when the task ended; a sign-in page there means the saved sign-in has expired. */
|
|
37
45
|
finalUrl: string | null;
|
|
46
|
+
/** The files the task downloaded; their bytes went to onDownload. */
|
|
47
|
+
downloads: {
|
|
48
|
+
name: string;
|
|
49
|
+
size: number;
|
|
50
|
+
}[];
|
|
38
51
|
}
|
|
39
52
|
export declare function createComputerUseTool(options: ComputerUseOptions): ({
|
|
40
53
|
deferLoading?: boolean;
|
package/dist/computer-use.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// agent (CUA) and waits for its result. Calls go to the CUA's task API, signed
|
|
3
3
|
// with SigV4 as the runtime's own role (ADR 0078). A saved sign-in is a runtime
|
|
4
4
|
// secret: its session goes with the task and the refreshed one is saved back
|
|
5
|
-
// to it (ADR 0090).
|
|
5
|
+
// to it (ADR 0090). Files the task downloads go to the app's onDownload, never
|
|
6
|
+
// to the model (ADR 0091).
|
|
6
7
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
7
8
|
import { jsonSchema, tool } from 'ai';
|
|
8
9
|
import { allowedHostsOf, computerUseApi, refused } from './computer-use-api.js';
|
|
@@ -71,7 +72,7 @@ export function createComputerUseTool(options) {
|
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
74
|
return tool({
|
|
74
|
-
description: 'Do one task in a web browser, such as filling in and submitting a form on a website. Describe the whole task in plain words, with the website address and any details it needs. Waits until the task ends and returns its status and a summary.',
|
|
75
|
+
description: 'Do one task in a web browser, such as filling in and submitting a form on a website. Describe the whole task in plain words, with the website address and any details it needs. Waits until the task ends and returns its status and a summary. Files the task downloads go to the app; the result lists their names.',
|
|
75
76
|
inputSchema: jsonSchema({ type: 'object', properties: { task: { type: 'string', minLength: 1 } }, required: ['task'], additionalProperties: false }),
|
|
76
77
|
execute: async ({ task }) => {
|
|
77
78
|
await api.post('/tasks', {
|
|
@@ -101,7 +102,17 @@ export function createComputerUseTool(options) {
|
|
|
101
102
|
if (answer.status === 'done' || answer.status === 'failed') {
|
|
102
103
|
if (answer.status === 'done' && session !== undefined && answer.session)
|
|
103
104
|
await runtimeSecrets.put(session, JSON.stringify(answer.session), transport);
|
|
104
|
-
|
|
105
|
+
const downloads = answer.downloads ?? [];
|
|
106
|
+
if (options.onDownload) {
|
|
107
|
+
for (const { name, contentType, size, url } of downloads) {
|
|
108
|
+
await options.progress(99, `Computer use download: ${name}`);
|
|
109
|
+
const response = await (options.fetch ?? fetch)(url);
|
|
110
|
+
if (response.status !== 200)
|
|
111
|
+
throw refused(`the download ${name}`, response.status, undefined);
|
|
112
|
+
await options.onDownload({ name, contentType, size, blob: await response.blob() });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { status: answer.status, summary: answer.summary ?? null, finalUrl: answer.final_url ?? null, downloads: downloads.map(({ name, size }) => ({ name, size })) };
|
|
105
116
|
}
|
|
106
117
|
if (answer.steps > steps || now() - reported >= HEARTBEAT_MS) {
|
|
107
118
|
steps = Math.max(steps, answer.steps);
|