SDK: support select_option and extract (#3850)

This commit is contained in:
Stanislav Novosad
2025-10-30 09:05:20 -06:00
committed by GitHub
parent ac069838c7
commit af9a5f31e4
21 changed files with 774 additions and 124 deletions

View File

@@ -1,5 +1,5 @@
# Reference
<details><summary><code>client.<a href="/src/Client.ts">deployScript</a>(scriptId, { ...params }) -> Skyvern.CreateScriptResponse</code></summary>
<details><summary><code>client.<a href="/src/Client.ts">runSdkAction</a>({ ...params }) -> Skyvern.RunSdkActionResponse</code></summary>
<dl>
<dd>
@@ -11,7 +11,7 @@
<dl>
<dd>
Deploy a script with updated files, creating a new version
Execute a single SDK action with the specified parameters
</dd>
</dl>
</dd>
@@ -26,11 +26,12 @@ Deploy a script with updated files, creating a new version
<dd>
```typescript
await client.deployScript("s_abc123", {
files: [{
path: "src/main.py",
content: "content"
}]
await client.runSdkAction({
"x-user-agent": "x-user-agent",
url: "url",
action: {
type: "ai_click"
}
});
```
@@ -47,15 +48,7 @@ await client.deployScript("s_abc123", {
<dl>
<dd>
**scriptId:** `string` — The unique identifier of the script
</dd>
</dl>
<dl>
<dd>
**request:** `Skyvern.DeployScriptRequest`
**request:** `Skyvern.RunSdkActionRequest`
</dd>
</dl>

View File

@@ -2202,4 +2202,101 @@ export class SkyvernClient {
});
}
}
/**
* Execute a single SDK action with the specified parameters
*
* @param {Skyvern.RunSdkActionRequest} request
* @param {SkyvernClient.RequestOptions} requestOptions - Request-specific configuration.
*
* @throws {@link Skyvern.BadRequestError}
* @throws {@link Skyvern.ForbiddenError}
* @throws {@link Skyvern.NotFoundError}
* @throws {@link Skyvern.UnprocessableEntityError}
*
* @example
* await client.runSdkAction({
* "x-user-agent": "x-user-agent",
* url: "url",
* action: {
* type: "ai_click"
* }
* })
*/
public runSdkAction(
request: Skyvern.RunSdkActionRequest,
requestOptions?: SkyvernClient.RequestOptions,
): core.HttpResponsePromise<Skyvern.RunSdkActionResponse> {
return core.HttpResponsePromise.fromPromise(this.__runSdkAction(request, requestOptions));
}
private async __runSdkAction(
request: Skyvern.RunSdkActionRequest,
requestOptions?: SkyvernClient.RequestOptions,
): Promise<core.WithRawResponse<Skyvern.RunSdkActionResponse>> {
const { "x-user-agent": userAgent, ..._body } = request;
const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
this._options?.headers,
mergeOnlyDefinedHeaders({
"x-user-agent": userAgent != null ? userAgent : undefined,
"x-api-key": requestOptions?.apiKey ?? this._options?.apiKey,
}),
requestOptions?.headers,
);
const _response = await core.fetcher({
url: core.url.join(
(await core.Supplier.get(this._options.baseUrl)) ??
(await core.Supplier.get(this._options.environment)) ??
environments.SkyvernEnvironment.Production,
"v1/sdk/run_action",
),
method: "POST",
headers: _headers,
contentType: "application/json",
queryParameters: requestOptions?.queryParams,
requestType: "json",
body: _body,
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
abortSignal: requestOptions?.abortSignal,
});
if (_response.ok) {
return { data: _response.body as Skyvern.RunSdkActionResponse, rawResponse: _response.rawResponse };
}
if (_response.error.reason === "status-code") {
switch (_response.error.statusCode) {
case 400:
throw new Skyvern.BadRequestError(_response.error.body as unknown, _response.rawResponse);
case 403:
throw new Skyvern.ForbiddenError(_response.error.body as unknown, _response.rawResponse);
case 404:
throw new Skyvern.NotFoundError(_response.error.body as unknown, _response.rawResponse);
case 422:
throw new Skyvern.UnprocessableEntityError(_response.error.body as unknown, _response.rawResponse);
default:
throw new errors.SkyvernError({
statusCode: _response.error.statusCode,
body: _response.error.body,
rawResponse: _response.rawResponse,
});
}
}
switch (_response.error.reason) {
case "non-json":
throw new errors.SkyvernError({
statusCode: _response.error.statusCode,
body: _response.error.rawBody,
rawResponse: _response.rawResponse,
});
case "timeout":
throw new errors.SkyvernTimeoutError("Timeout exceeded when calling POST /v1/sdk/run_action.");
case "unknown":
throw new errors.SkyvernError({
message: _response.error.errorMessage,
rawResponse: _response.rawResponse,
});
}
}
}

View File

@@ -0,0 +1,27 @@
// This file was auto-generated by Fern from our API Definition.
import type * as Skyvern from "../../index.js";
/**
* @example
* {
* "x-user-agent": "x-user-agent",
* url: "url",
* action: {
* type: "ai_click"
* }
* }
*/
export interface RunSdkActionRequest {
"x-user-agent"?: string;
/** The URL where the action should be executed */
url: string;
/** The browser session ID */
browser_session_id?: string;
/** The browser address */
browser_address?: string;
/** Optional workflow run ID to continue an existing workflow run */
workflow_run_id?: string;
/** The action to execute with its specific parameters */
action: Skyvern.SdkAction;
}

View File

@@ -7,6 +7,7 @@ export type { GetRunArtifactsRequest } from "./GetRunArtifactsRequest.js";
export type { GetScriptsRequest } from "./GetScriptsRequest.js";
export type { GetWorkflowsRequest } from "./GetWorkflowsRequest.js";
export type { LoginRequest } from "./LoginRequest.js";
export type { RunSdkActionRequest } from "./RunSdkActionRequest.js";
export type { RunTaskRequest } from "./RunTaskRequest.js";
export type { RunWorkflowRequest } from "./RunWorkflowRequest.js";
export type { TotpCodeCreate } from "./TotpCodeCreate.js";

View File

@@ -0,0 +1,19 @@
// This file was auto-generated by Fern from our API Definition.
export interface ClickAction {
/** CSS selector for the element */
selector?: string;
/** The intention or goal of the click */
intention?: string;
/** Additional context data */
data?: ClickAction.Data;
/** Timeout in milliseconds */
timeout?: number;
}
export namespace ClickAction {
/**
* Additional context data
*/
export type Data = string | Record<string, unknown>;
}

View File

@@ -0,0 +1,25 @@
// This file was auto-generated by Fern from our API Definition.
export interface ExtractAction {
/** Extraction prompt */
prompt?: string;
/** Schema for extraction */
extract_schema?: ExtractAction.ExtractSchema;
/** Error code mapping for extraction */
error_code_mapping?: Record<string, string | undefined>;
/** The intention or goal of the extraction */
intention?: string;
/** Additional context data */
data?: ExtractAction.Data;
}
export namespace ExtractAction {
/**
* Schema for extraction
*/
export type ExtractSchema = Record<string, unknown> | unknown[] | string;
/**
* Additional context data
*/
export type Data = string | Record<string, unknown>;
}

View File

@@ -0,0 +1,25 @@
// This file was auto-generated by Fern from our API Definition.
export interface InputTextAction {
/** CSS selector for the element */
selector?: string;
/** Value to input */
value?: string;
/** The intention or goal of the input */
intention?: string;
/** Additional context data */
data?: InputTextAction.Data;
/** TOTP identifier for input_text actions */
totp_identifier?: string;
/** TOTP URL for input_text actions */
totp_url?: string;
/** Timeout in milliseconds */
timeout?: number;
}
export namespace InputTextAction {
/**
* Additional context data
*/
export type Data = string | Record<string, unknown>;
}

View File

@@ -0,0 +1,15 @@
// This file was auto-generated by Fern from our API Definition.
export interface RunSdkActionResponse {
/** The workflow run ID used for this action */
workflow_run_id: string;
/** The result from the action (e.g., selector, value, extracted data) */
result?: RunSdkActionResponse.Result;
}
export namespace RunSdkActionResponse {
/**
* The result from the action (e.g., selector, value, extracted data)
*/
export type Result = string | Record<string, unknown> | unknown[] | number | boolean;
}

View File

@@ -0,0 +1,27 @@
// This file was auto-generated by Fern from our API Definition.
import type * as Skyvern from "../index.js";
export type SdkAction =
| Skyvern.SdkAction.AiClick
| Skyvern.SdkAction.AiInputText
| Skyvern.SdkAction.AiSelectOption
| Skyvern.SdkAction.Extract;
export namespace SdkAction {
export interface AiClick extends Skyvern.ClickAction {
type: "ai_click";
}
export interface AiInputText extends Skyvern.InputTextAction {
type: "ai_input_text";
}
export interface AiSelectOption extends Skyvern.SelectOptionAction {
type: "ai_select_option";
}
export interface Extract extends Skyvern.ExtractAction {
type: "extract";
}
}

View File

@@ -0,0 +1,21 @@
// This file was auto-generated by Fern from our API Definition.
export interface SelectOptionAction {
/** CSS selector for the element */
selector?: string;
/** Value to select */
value?: string;
/** The intention or goal of the selection */
intention?: string;
/** Additional context data */
data?: SelectOptionAction.Data;
/** Timeout in milliseconds */
timeout?: number;
}
export namespace SelectOptionAction {
/**
* Additional context data
*/
export type Data = string | Record<string, unknown>;
}

View File

@@ -19,6 +19,7 @@ export * from "./BitwardenSensitiveInformationParameter.js";
export * from "./BitwardenSensitiveInformationParameterYaml.js";
export * from "./BlockType.js";
export * from "./BrowserSessionResponse.js";
export * from "./ClickAction.js";
export * from "./CodeBlock.js";
export * from "./CodeBlockParametersItem.js";
export * from "./CodeBlockYaml.js";
@@ -33,6 +34,7 @@ export * from "./CredentialTypeOutput.js";
export * from "./CreditCardCredentialResponse.js";
export * from "./DownloadToS3Block.js";
export * from "./DownloadToS3BlockYaml.js";
export * from "./ExtractAction.js";
export * from "./ExtractionBlock.js";
export * from "./ExtractionBlockParametersItem.js";
export * from "./ExtractionBlockYaml.js";
@@ -62,6 +64,7 @@ export * from "./HumanInteractionBlock.js";
export * from "./HumanInteractionBlockParametersItem.js";
export * from "./HumanInteractionBlockYaml.js";
export * from "./InputOrSelectContext.js";
export * from "./InputTextAction.js";
export * from "./LoginBlock.js";
export * from "./LoginBlockParametersItem.js";
export * from "./LoginBlockYaml.js";
@@ -80,11 +83,14 @@ export * from "./PdfParserBlock.js";
export * from "./PdfParserBlockYaml.js";
export * from "./ProxyLocation.js";
export * from "./RunEngine.js";
export * from "./RunSdkActionResponse.js";
export * from "./RunStatus.js";
export * from "./Script.js";
export * from "./ScriptFileCreate.js";
export * from "./ScriptRunResponse.js";
export * from "./SdkAction.js";
export * from "./SelectOption.js";
export * from "./SelectOptionAction.js";
export * from "./SendEmailBlock.js";
export * from "./SendEmailBlockYaml.js";
export * from "./SkyvernForgeSdkSchemasCredentialsCredentialType.js";

View File

@@ -2429,4 +2429,128 @@ describe("SkyvernClient", () => {
});
}).rejects.toThrow(Skyvern.UnprocessableEntityError);
});
test("run_sdk_action (1)", async () => {
const server = mockServerPool.createServer();
const client = new SkyvernClient({ apiKey: "test", environment: server.baseUrl });
const rawRequestBody = { url: "url", action: { type: "ai_click" } };
const rawResponseBody = { workflow_run_id: "workflow_run_id", result: "result" };
server
.mockEndpoint()
.post("/v1/sdk/run_action")
.header("x-user-agent", "x-user-agent")
.jsonBody(rawRequestBody)
.respondWith()
.statusCode(200)
.jsonBody(rawResponseBody)
.build();
const response = await client.runSdkAction({
"x-user-agent": "x-user-agent",
url: "url",
action: {
type: "ai_click",
},
});
expect(response).toEqual({
workflow_run_id: "workflow_run_id",
result: "result",
});
});
test("run_sdk_action (2)", async () => {
const server = mockServerPool.createServer();
const client = new SkyvernClient({ apiKey: "test", environment: server.baseUrl });
const rawRequestBody = { url: "url", action: { type: "ai_click" } };
const rawResponseBody = { key: "value" };
server
.mockEndpoint()
.post("/v1/sdk/run_action")
.jsonBody(rawRequestBody)
.respondWith()
.statusCode(400)
.jsonBody(rawResponseBody)
.build();
await expect(async () => {
return await client.runSdkAction({
url: "url",
action: {
type: "ai_click",
},
});
}).rejects.toThrow(Skyvern.BadRequestError);
});
test("run_sdk_action (3)", async () => {
const server = mockServerPool.createServer();
const client = new SkyvernClient({ apiKey: "test", environment: server.baseUrl });
const rawRequestBody = { url: "url", action: { type: "ai_click" } };
const rawResponseBody = { key: "value" };
server
.mockEndpoint()
.post("/v1/sdk/run_action")
.jsonBody(rawRequestBody)
.respondWith()
.statusCode(403)
.jsonBody(rawResponseBody)
.build();
await expect(async () => {
return await client.runSdkAction({
url: "url",
action: {
type: "ai_click",
},
});
}).rejects.toThrow(Skyvern.ForbiddenError);
});
test("run_sdk_action (4)", async () => {
const server = mockServerPool.createServer();
const client = new SkyvernClient({ apiKey: "test", environment: server.baseUrl });
const rawRequestBody = { url: "url", action: { type: "ai_click" } };
const rawResponseBody = { key: "value" };
server
.mockEndpoint()
.post("/v1/sdk/run_action")
.jsonBody(rawRequestBody)
.respondWith()
.statusCode(404)
.jsonBody(rawResponseBody)
.build();
await expect(async () => {
return await client.runSdkAction({
url: "url",
action: {
type: "ai_click",
},
});
}).rejects.toThrow(Skyvern.NotFoundError);
});
test("run_sdk_action (5)", async () => {
const server = mockServerPool.createServer();
const client = new SkyvernClient({ apiKey: "test", environment: server.baseUrl });
const rawRequestBody = { url: "url", action: { type: "ai_click" } };
const rawResponseBody = { key: "value" };
server
.mockEndpoint()
.post("/v1/sdk/run_action")
.jsonBody(rawRequestBody)
.respondWith()
.statusCode(422)
.jsonBody(rawResponseBody)
.build();
await expect(async () => {
return await client.runSdkAction({
url: "url",
action: {
type: "ai_click",
},
});
}).rejects.toThrow(Skyvern.UnprocessableEntityError);
});
});