From f3fdc89088feeb32983da39700e47e922f767126 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 22:00:26 +0000 Subject: [PATCH 01/10] refactor(browser): remove persistence option UI --- .stats.yml | 6 ++--- README.md | 34 +++++++++++++--------------- src/resources/browser-pools.ts | 3 ++- src/resources/browsers/browsers.ts | 36 +++++++++++++++--------------- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7792bb0..a0095f1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-003e9afa15f0765009d2c7d34e8eb62268d818e628e3c84361b21138e30cc423.yml -openapi_spec_hash: c1b8309f60385bf2b02d245363ca47c1 -config_hash: a4124701ae0a474e580d7416adbcfb00 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-cbef7e4fef29ad40af5c767aceb762ee68811c2287f255c05d2ee44a9a9247a2.yml +openapi_spec_hash: 467e61e072773ec9f2d49c7dd3de8c2f +config_hash: 6dbe88d2ba9df1ec46cedbfdb7d00000 diff --git a/README.md b/README.md index 0018d91..3007e65 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ const client = new Kernel({ environment: 'development', // defaults to 'production' }); -const browser = await client.browsers.create({ persistence: { id: 'browser-for-user-1234' } }); +const browser = await client.browsers.create({ stealth: true }); console.log(browser.session_id); ``` @@ -45,7 +45,7 @@ const client = new Kernel({ environment: 'development', // defaults to 'production' }); -const params: Kernel.BrowserCreateParams = { persistence: { id: 'browser-for-user-1234' } }; +const params: Kernel.BrowserCreateParams = { stealth: true }; const browser: Kernel.BrowserCreateResponse = await client.browsers.create(params); ``` @@ -88,17 +88,15 @@ a subclass of `APIError` will be thrown: ```ts -const browser = await client.browsers - .create({ persistence: { id: 'browser-for-user-1234' } }) - .catch(async (err) => { - if (err instanceof Kernel.APIError) { - console.log(err.status); // 400 - console.log(err.name); // BadRequestError - console.log(err.headers); // {server: 'nginx', ...} - } else { - throw err; - } - }); +const browser = await client.browsers.create({ stealth: true }).catch(async (err) => { + if (err instanceof Kernel.APIError) { + console.log(err.status); // 400 + console.log(err.name); // BadRequestError + console.log(err.headers); // {server: 'nginx', ...} + } else { + throw err; + } +}); ``` Error codes are as follows: @@ -130,7 +128,7 @@ const client = new Kernel({ }); // Or, configure per-request: -await client.browsers.create({ persistence: { id: 'browser-for-user-1234' } }, { +await client.browsers.create({ stealth: true }, { maxRetries: 5, }); ``` @@ -147,7 +145,7 @@ const client = new Kernel({ }); // Override per-request: -await client.browsers.create({ persistence: { id: 'browser-for-user-1234' } }, { +await client.browsers.create({ stealth: true }, { timeout: 5 * 1000, }); ``` @@ -201,13 +199,11 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse ```ts const client = new Kernel(); -const response = await client.browsers.create({ persistence: { id: 'browser-for-user-1234' } }).asResponse(); +const response = await client.browsers.create({ stealth: true }).asResponse(); console.log(response.headers.get('X-My-Header')); console.log(response.statusText); // access the underlying Response object -const { data: browser, response: raw } = await client.browsers - .create({ persistence: { id: 'browser-for-user-1234' } }) - .withResponse(); +const { data: browser, response: raw } = await client.browsers.create({ stealth: true }).withResponse(); console.log(raw.headers.get('X-My-Header')); console.log(browser.session_id); ``` diff --git a/src/resources/browser-pools.ts b/src/resources/browser-pools.ts index be28ad0..d60dbe7 100644 --- a/src/resources/browser-pools.ts +++ b/src/resources/browser-pools.ts @@ -339,7 +339,8 @@ export interface BrowserPoolAcquireResponse { kiosk_mode?: boolean; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ persistence?: BrowsersAPI.BrowserPersistence; diff --git a/src/resources/browsers/browsers.ts b/src/resources/browsers/browsers.ts index d3f8b3d..0fcd3eb 100644 --- a/src/resources/browsers/browsers.ts +++ b/src/resources/browsers/browsers.ts @@ -127,14 +127,10 @@ export class Browsers extends APIResource { } /** - * Delete a persistent browser session by its persistent_id. + * DEPRECATED: Use DELETE /browsers/{id} instead. Delete a persistent browser + * session by its persistent_id. * - * @example - * ```ts - * await client.browsers.delete({ - * persistent_id: 'persistent_id', - * }); - * ``` + * @deprecated */ delete(params: BrowserDeleteParams, options?: RequestOptions): APIPromise { const { persistent_id } = params; @@ -192,11 +188,12 @@ export class Browsers extends APIResource { export type BrowserListResponsesOffsetPagination = OffsetPagination; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ export interface BrowserPersistence { /** - * Unique identifier for the persistent browser session. + * DEPRECATED: Unique identifier for the persistent browser session. */ id: string; } @@ -279,7 +276,8 @@ export interface BrowserCreateResponse { kiosk_mode?: boolean; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ persistence?: BrowserPersistence; @@ -354,7 +352,8 @@ export interface BrowserRetrieveResponse { kiosk_mode?: boolean; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ persistence?: BrowserPersistence; @@ -429,7 +428,8 @@ export interface BrowserListResponse { kiosk_mode?: boolean; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ persistence?: BrowserPersistence; @@ -480,7 +480,8 @@ export interface BrowserCreateParams { kiosk_mode?: boolean; /** - * Optional persistence configuration for the browser session. + * @deprecated DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles + * instead. */ persistence?: BrowserPersistence; @@ -505,11 +506,10 @@ export interface BrowserCreateParams { /** * The number of seconds of inactivity before the browser session is terminated. - * Only applicable to non-persistent browsers. Activity includes CDP connections - * and live view connections. Defaults to 60 seconds. Minimum allowed is 10 - * seconds. Maximum allowed is 259200 (72 hours). We check for inactivity every 5 - * seconds, so the actual timeout behavior you will see is +/- 5 seconds around the - * specified value. + * Activity includes CDP connections and live view connections. Defaults to 60 + * seconds. Minimum allowed is 10 seconds. Maximum allowed is 259200 (72 hours). We + * check for inactivity every 5 seconds, so the actual timeout behavior you will + * see is +/- 5 seconds around the specified value. */ timeout_seconds?: number; From 7c8a4641cb87a76a3248e2d1df713df929957262 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 22:56:11 +0000 Subject: [PATCH 02/10] feat: [wip] Browser pools polish pass --- .stats.yml | 4 +-- src/resources/browser-pools.ts | 44 +++++++++++++++--------------- src/resources/browsers/browsers.ts | 40 +++++++++++++-------------- src/resources/shared.ts | 10 +++---- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.stats.yml b/.stats.yml index a0095f1..44c807a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-cbef7e4fef29ad40af5c767aceb762ee68811c2287f255c05d2ee44a9a9247a2.yml -openapi_spec_hash: 467e61e072773ec9f2d49c7dd3de8c2f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3a68acd8c46e121c66be5b4c30bb4e962967840ca0f31070905baa39635fbc2d.yml +openapi_spec_hash: 9453963fbb01de3e0afb462b16cdf115 config_hash: 6dbe88d2ba9df1ec46cedbfdb7d00000 diff --git a/src/resources/browser-pools.ts b/src/resources/browser-pools.ts index d60dbe7..6aa09c2 100644 --- a/src/resources/browser-pools.ts +++ b/src/resources/browser-pools.ts @@ -266,11 +266,11 @@ export interface BrowserPoolRequest { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -284,7 +284,7 @@ export interface BrowserPoolRequest { export interface BrowserPoolUpdateRequest extends BrowserPoolRequest { /** * Whether to discard all idle browsers and rebuild the pool immediately. Defaults - * to true. + * to false. */ discard_all_idle?: boolean; } @@ -356,11 +356,11 @@ export interface BrowserPoolAcquireResponse { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -426,11 +426,11 @@ export interface BrowserPoolCreateParams { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -445,7 +445,7 @@ export interface BrowserPoolUpdateParams { /** * Whether to discard all idle browsers and rebuild the pool immediately. Defaults - * to true. + * to false. */ discard_all_idle?: boolean; @@ -502,11 +502,11 @@ export interface BrowserPoolUpdateParams { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ diff --git a/src/resources/browsers/browsers.ts b/src/resources/browsers/browsers.ts index 0fcd3eb..b42c383 100644 --- a/src/resources/browsers/browsers.ts +++ b/src/resources/browsers/browsers.ts @@ -293,11 +293,11 @@ export interface BrowserCreateResponse { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -369,11 +369,11 @@ export interface BrowserRetrieveResponse { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -445,11 +445,11 @@ export interface BrowserListResponse { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ @@ -515,11 +515,11 @@ export interface BrowserCreateParams { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ diff --git a/src/resources/shared.ts b/src/resources/shared.ts index 13cbc0b..3a3112b 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -53,11 +53,11 @@ export interface BrowserProfile { /** * Initial browser window size in pixels with optional refresh rate. If omitted, - * image defaults apply (commonly 1024x768@60). Only specific viewport - * configurations are supported. The server will reject unsupported combinations. - * Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, - * 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will - * be automatically determined from the width and height if they match a supported + * image defaults apply (1920x1080@25). Only specific viewport configurations are + * supported. The server will reject unsupported combinations. Supported + * resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, + * 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will be + * automatically determined from the width and height if they match a supported * configuration exactly. Note: Higher resolutions may affect the responsiveness of * live view browser */ From 7ea4b076cc5255f76945ae370a8f686349a28a30 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 02:01:14 +0000 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20Enhance=20agent=20authentication?= =?UTF-8?q?=20with=20optional=20login=20page=20URL=20and=20auth=20ch?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stats.yml | 8 +- api.md | 31 ++ src/client.ts | 5 + src/resources/agents.ts | 3 + src/resources/agents/agents.ts | 33 ++ src/resources/agents/auth.ts | 3 + src/resources/agents/auth/auth.ts | 303 ++++++++++++++++++ src/resources/agents/auth/index.ts | 19 ++ src/resources/agents/auth/invocations.ts | 139 ++++++++ src/resources/agents/index.ts | 13 + src/resources/index.ts | 1 + tests/api-resources/agents/auth/auth.test.ts | 48 +++ .../agents/auth/invocations.test.ts | 84 +++++ 13 files changed, 686 insertions(+), 4 deletions(-) create mode 100644 src/resources/agents.ts create mode 100644 src/resources/agents/agents.ts create mode 100644 src/resources/agents/auth.ts create mode 100644 src/resources/agents/auth/auth.ts create mode 100644 src/resources/agents/auth/index.ts create mode 100644 src/resources/agents/auth/invocations.ts create mode 100644 src/resources/agents/index.ts create mode 100644 tests/api-resources/agents/auth/auth.test.ts create mode 100644 tests/api-resources/agents/auth/invocations.test.ts diff --git a/.stats.yml b/.stats.yml index 44c807a..0c474bb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3a68acd8c46e121c66be5b4c30bb4e962967840ca0f31070905baa39635fbc2d.yml -openapi_spec_hash: 9453963fbb01de3e0afb462b16cdf115 -config_hash: 6dbe88d2ba9df1ec46cedbfdb7d00000 +configured_endpoints: 80 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8a37652fa586b8932466d16285359a89988505f850787f8257d0c4c7053da173.yml +openapi_spec_hash: 042765a113f6d08109e8146b302323ec +config_hash: 113f1e5bc3567628a5d51c70bc00969d diff --git a/api.md b/api.md index c3c1b6e..6d64516 100644 --- a/api.md +++ b/api.md @@ -246,3 +246,34 @@ Methods: - client.browserPools.acquire(idOrName, { ...params }) -> BrowserPoolAcquireResponse - client.browserPools.flush(idOrName) -> void - client.browserPools.release(idOrName, { ...params }) -> void + +# Agents + +## Auth + +Types: + +- AgentAuthDiscoverResponse +- AgentAuthInvocationResponse +- AgentAuthStartResponse +- AgentAuthSubmitResponse +- AuthAgent +- DiscoveredField + +Methods: + +- client.agents.auth.retrieve(id) -> AuthAgent +- client.agents.auth.start({ ...params }) -> AgentAuthStartResponse + +### Invocations + +Types: + +- InvocationExchangeResponse + +Methods: + +- client.agents.auth.invocations.retrieve(invocationID) -> AgentAuthInvocationResponse +- client.agents.auth.invocations.discover(invocationID, { ...params }) -> AgentAuthDiscoverResponse +- client.agents.auth.invocations.exchange(invocationID, { ...params }) -> InvocationExchangeResponse +- client.agents.auth.invocations.submit(invocationID, { ...params }) -> AgentAuthSubmitResponse diff --git a/src/client.ts b/src/client.ts index a0dffa0..dd80bb3 100644 --- a/src/client.ts +++ b/src/client.ts @@ -76,6 +76,7 @@ import { ProxyListResponse, ProxyRetrieveResponse, } from './resources/proxies'; +import { Agents } from './resources/agents/agents'; import { BrowserCreateParams, BrowserCreateResponse, @@ -859,6 +860,7 @@ export class Kernel { proxies: API.Proxies = new API.Proxies(this); extensions: API.Extensions = new API.Extensions(this); browserPools: API.BrowserPools = new API.BrowserPools(this); + agents: API.Agents = new API.Agents(this); } Kernel.Deployments = Deployments; @@ -869,6 +871,7 @@ Kernel.Profiles = Profiles; Kernel.Proxies = Proxies; Kernel.Extensions = Extensions; Kernel.BrowserPools = BrowserPools; +Kernel.Agents = Agents; export declare namespace Kernel { export type RequestOptions = Opts.RequestOptions; @@ -966,6 +969,8 @@ export declare namespace Kernel { type BrowserPoolReleaseParams as BrowserPoolReleaseParams, }; + export { Agents as Agents }; + export type AppAction = API.AppAction; export type BrowserExtension = API.BrowserExtension; export type BrowserProfile = API.BrowserProfile; diff --git a/src/resources/agents.ts b/src/resources/agents.ts new file mode 100644 index 0000000..0c43db0 --- /dev/null +++ b/src/resources/agents.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './agents/index'; diff --git a/src/resources/agents/agents.ts b/src/resources/agents/agents.ts new file mode 100644 index 0000000..5155028 --- /dev/null +++ b/src/resources/agents/agents.ts @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as AuthAPI from './auth/auth'; +import { + AgentAuthDiscoverResponse, + AgentAuthInvocationResponse, + AgentAuthStartResponse, + AgentAuthSubmitResponse, + Auth, + AuthAgent, + AuthStartParams, + DiscoveredField, +} from './auth/auth'; + +export class Agents extends APIResource { + auth: AuthAPI.Auth = new AuthAPI.Auth(this._client); +} + +Agents.Auth = Auth; + +export declare namespace Agents { + export { + Auth as Auth, + type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, + type AgentAuthInvocationResponse as AgentAuthInvocationResponse, + type AgentAuthStartResponse as AgentAuthStartResponse, + type AgentAuthSubmitResponse as AgentAuthSubmitResponse, + type AuthAgent as AuthAgent, + type DiscoveredField as DiscoveredField, + type AuthStartParams as AuthStartParams, + }; +} diff --git a/src/resources/agents/auth.ts b/src/resources/agents/auth.ts new file mode 100644 index 0000000..b64faa1 --- /dev/null +++ b/src/resources/agents/auth.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './auth/index'; diff --git a/src/resources/agents/auth/auth.ts b/src/resources/agents/auth/auth.ts new file mode 100644 index 0000000..65d847e --- /dev/null +++ b/src/resources/agents/auth/auth.ts @@ -0,0 +1,303 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as InvocationsAPI from './invocations'; +import { + InvocationDiscoverParams, + InvocationExchangeParams, + InvocationExchangeResponse, + InvocationSubmitParams, + Invocations, +} from './invocations'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +export class Auth extends APIResource { + invocations: InvocationsAPI.Invocations = new InvocationsAPI.Invocations(this._client); + + /** + * Retrieve an auth agent by its ID. Returns the current authentication status of + * the managed profile. + * + * @example + * ```ts + * const authAgent = await client.agents.auth.retrieve('id'); + * ``` + */ + retrieve(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/agents/auth/${id}`, options); + } + + /** + * Creates a browser session and returns a handoff code for the hosted flow. Uses + * standard API key or JWT authentication (not the JWT returned by the exchange + * endpoint). + * + * @example + * ```ts + * const agentAuthStartResponse = + * await client.agents.auth.start({ + * profile_name: 'auth-abc123', + * target_domain: 'doordash.com', + * }); + * ``` + */ + start(body: AuthStartParams, options?: RequestOptions): APIPromise { + return this._client.post('/agents/auth/start', { body, ...options }); + } +} + +/** + * Response from discover endpoint matching AuthBlueprint schema + */ +export interface AgentAuthDiscoverResponse { + /** + * Whether discovery succeeded + */ + success: boolean; + + /** + * Error message if discovery failed + */ + error_message?: string; + + /** + * Discovered form fields (present when success is true) + */ + fields?: Array; + + /** + * Whether user is already logged in + */ + logged_in?: boolean; + + /** + * URL of the discovered login page + */ + login_url?: string; + + /** + * Title of the login page + */ + page_title?: string; +} + +/** + * Response from get invocation endpoint + */ +export interface AgentAuthInvocationResponse { + /** + * App name (org name at time of invocation creation) + */ + app_name: string; + + /** + * When the handoff code expires + */ + expires_at: string; + + /** + * Invocation status + */ + status: 'IN_PROGRESS' | 'SUCCESS' | 'EXPIRED' | 'CANCELED'; + + /** + * Target domain for authentication + */ + target_domain: string; +} + +/** + * Response from starting an agent authentication invocation + */ +export interface AgentAuthStartResponse { + /** + * Unique identifier for the auth agent managing this domain/profile + */ + auth_agent_id: string; + + /** + * When the handoff code expires + */ + expires_at: string; + + /** + * One-time code for handoff + */ + handoff_code: string; + + /** + * URL to redirect user to + */ + hosted_url: string; + + /** + * Unique identifier for the invocation + */ + invocation_id: string; +} + +/** + * Response from submit endpoint matching SubmitResult schema + */ +export interface AgentAuthSubmitResponse { + /** + * Whether submission succeeded + */ + success: boolean; + + /** + * Additional fields needed (e.g., OTP) - present when needs_additional_auth is + * true + */ + additional_fields?: Array; + + /** + * App name (only present when logged_in is true) + */ + app_name?: string; + + /** + * Error message if submission failed + */ + error_message?: string; + + /** + * Whether user is now logged in + */ + logged_in?: boolean; + + /** + * Whether additional authentication fields are needed + */ + needs_additional_auth?: boolean; + + /** + * Target domain (only present when logged_in is true) + */ + target_domain?: string; +} + +/** + * An auth agent that manages authentication for a specific domain and profile + * combination + */ +export interface AuthAgent { + /** + * Unique identifier for the auth agent + */ + id: string; + + /** + * Target domain for authentication + */ + domain: string; + + /** + * Name of the profile associated with this auth agent + */ + profile_name: string; + + /** + * Current authentication status of the managed profile + */ + status: 'AUTHENTICATED' | 'NEEDS_AUTH'; +} + +/** + * A discovered form field + */ +export interface DiscoveredField { + /** + * Field label + */ + label: string; + + /** + * Field name + */ + name: string; + + /** + * CSS selector for the field + */ + selector: string; + + /** + * Field type + */ + type: 'text' | 'email' | 'password' | 'tel' | 'number' | 'url' | 'code'; + + /** + * Field placeholder + */ + placeholder?: string; + + /** + * Whether field is required + */ + required?: boolean; +} + +export interface AuthStartParams { + /** + * Name of the profile to use for this flow + */ + profile_name: string; + + /** + * Target domain for authentication + */ + target_domain: string; + + /** + * Optional logo URL for the application + */ + app_logo_url?: string; + + /** + * Optional login page URL. If provided, will be stored on the agent and used to + * skip Phase 1 discovery in future invocations. + */ + login_url?: string; + + /** + * Optional proxy configuration + */ + proxy?: AuthStartParams.Proxy; +} + +export namespace AuthStartParams { + /** + * Optional proxy configuration + */ + export interface Proxy { + /** + * ID of the proxy to use + */ + proxy_id?: string; + } +} + +Auth.Invocations = Invocations; + +export declare namespace Auth { + export { + type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, + type AgentAuthInvocationResponse as AgentAuthInvocationResponse, + type AgentAuthStartResponse as AgentAuthStartResponse, + type AgentAuthSubmitResponse as AgentAuthSubmitResponse, + type AuthAgent as AuthAgent, + type DiscoveredField as DiscoveredField, + type AuthStartParams as AuthStartParams, + }; + + export { + Invocations as Invocations, + type InvocationExchangeResponse as InvocationExchangeResponse, + type InvocationDiscoverParams as InvocationDiscoverParams, + type InvocationExchangeParams as InvocationExchangeParams, + type InvocationSubmitParams as InvocationSubmitParams, + }; +} diff --git a/src/resources/agents/auth/index.ts b/src/resources/agents/auth/index.ts new file mode 100644 index 0000000..b364643 --- /dev/null +++ b/src/resources/agents/auth/index.ts @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Auth, + type AgentAuthDiscoverResponse, + type AgentAuthInvocationResponse, + type AgentAuthStartResponse, + type AgentAuthSubmitResponse, + type AuthAgent, + type DiscoveredField, + type AuthStartParams, +} from './auth'; +export { + Invocations, + type InvocationExchangeResponse, + type InvocationDiscoverParams, + type InvocationExchangeParams, + type InvocationSubmitParams, +} from './invocations'; diff --git a/src/resources/agents/auth/invocations.ts b/src/resources/agents/auth/invocations.ts new file mode 100644 index 0000000..4c87d5d --- /dev/null +++ b/src/resources/agents/auth/invocations.ts @@ -0,0 +1,139 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as AuthAPI from './auth'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +export class Invocations extends APIResource { + /** + * Returns invocation details including app_name and target_domain. Uses the JWT + * returned by the exchange endpoint, or standard API key or JWT authentication. + * + * @example + * ```ts + * const agentAuthInvocationResponse = + * await client.agents.auth.invocations.retrieve( + * 'invocation_id', + * ); + * ``` + */ + retrieve(invocationID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/agents/auth/invocations/${invocationID}`, options); + } + + /** + * Inspects the target site to detect logged-in state or discover required fields. + * Returns 200 with success: true when fields are found, or 4xx/5xx for failures. + * Requires the JWT returned by the exchange endpoint. + * + * @example + * ```ts + * const agentAuthDiscoverResponse = + * await client.agents.auth.invocations.discover( + * 'invocation_id', + * ); + * ``` + */ + discover( + invocationID: string, + body: InvocationDiscoverParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/agents/auth/invocations/${invocationID}/discover`, { body, ...options }); + } + + /** + * Validates the handoff code and returns a JWT token for subsequent requests. No + * authentication required (the handoff code serves as the credential). + * + * @example + * ```ts + * const response = + * await client.agents.auth.invocations.exchange( + * 'invocation_id', + * { code: 'abc123xyz' }, + * ); + * ``` + */ + exchange( + invocationID: string, + body: InvocationExchangeParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/agents/auth/invocations/${invocationID}/exchange`, { body, ...options }); + } + + /** + * Submits field values for the discovered login form and may return additional + * auth fields or success. Requires the JWT returned by the exchange endpoint. + * + * @example + * ```ts + * const agentAuthSubmitResponse = + * await client.agents.auth.invocations.submit( + * 'invocation_id', + * { + * field_values: { + * email: 'user@example.com', + * password: '********', + * }, + * }, + * ); + * ``` + */ + submit( + invocationID: string, + body: InvocationSubmitParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/agents/auth/invocations/${invocationID}/submit`, { body, ...options }); + } +} + +/** + * Response from exchange endpoint + */ +export interface InvocationExchangeResponse { + /** + * Invocation ID + */ + invocation_id: string; + + /** + * JWT token with invocation_id claim (30 minute TTL) + */ + jwt: string; +} + +export interface InvocationDiscoverParams { + /** + * Optional login page URL. If provided, will override the stored login URL for + * this discovery invocation and skip Phase 1 discovery. + */ + login_url?: string; +} + +export interface InvocationExchangeParams { + /** + * Handoff code from start endpoint + */ + code: string; +} + +export interface InvocationSubmitParams { + /** + * Values for the discovered login fields + */ + field_values: { [key: string]: string }; +} + +export declare namespace Invocations { + export { + type InvocationExchangeResponse as InvocationExchangeResponse, + type InvocationDiscoverParams as InvocationDiscoverParams, + type InvocationExchangeParams as InvocationExchangeParams, + type InvocationSubmitParams as InvocationSubmitParams, + }; +} diff --git a/src/resources/agents/index.ts b/src/resources/agents/index.ts new file mode 100644 index 0000000..86baf26 --- /dev/null +++ b/src/resources/agents/index.ts @@ -0,0 +1,13 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Agents } from './agents'; +export { + Auth, + type AgentAuthDiscoverResponse, + type AgentAuthInvocationResponse, + type AgentAuthStartResponse, + type AgentAuthSubmitResponse, + type AuthAgent, + type DiscoveredField, + type AuthStartParams, +} from './auth/index'; diff --git a/src/resources/index.ts b/src/resources/index.ts index 420e5e2..bab015b 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export * from './shared'; +export { Agents } from './agents/agents'; export { Apps, type AppListResponse, diff --git a/tests/api-resources/agents/auth/auth.test.ts b/tests/api-resources/agents/auth/auth.test.ts new file mode 100644 index 0000000..d0007db --- /dev/null +++ b/tests/api-resources/agents/auth/auth.test.ts @@ -0,0 +1,48 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource auth', () => { + // Prism tests are disabled + test.skip('retrieve', async () => { + const responsePromise = client.agents.auth.retrieve('id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('start: only required params', async () => { + const responsePromise = client.agents.auth.start({ + profile_name: 'auth-abc123', + target_domain: 'doordash.com', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('start: required and optional params', async () => { + const response = await client.agents.auth.start({ + profile_name: 'auth-abc123', + target_domain: 'doordash.com', + app_logo_url: 'https://example.com/logo.png', + login_url: 'https://doordash.com/account/login', + proxy: { proxy_id: 'proxy_id' }, + }); + }); +}); diff --git a/tests/api-resources/agents/auth/invocations.test.ts b/tests/api-resources/agents/auth/invocations.test.ts new file mode 100644 index 0000000..33a58f9 --- /dev/null +++ b/tests/api-resources/agents/auth/invocations.test.ts @@ -0,0 +1,84 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Kernel from '@onkernel/sdk'; + +const client = new Kernel({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource invocations', () => { + // Prism tests are disabled + test.skip('retrieve', async () => { + const responsePromise = client.agents.auth.invocations.retrieve('invocation_id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('discover', async () => { + const responsePromise = client.agents.auth.invocations.discover('invocation_id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('discover: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.agents.auth.invocations.discover( + 'invocation_id', + { login_url: 'https://doordash.com/account/login' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Kernel.NotFoundError); + }); + + // Prism tests are disabled + test.skip('exchange: only required params', async () => { + const responsePromise = client.agents.auth.invocations.exchange('invocation_id', { code: 'abc123xyz' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('exchange: required and optional params', async () => { + const response = await client.agents.auth.invocations.exchange('invocation_id', { code: 'abc123xyz' }); + }); + + // Prism tests are disabled + test.skip('submit: only required params', async () => { + const responsePromise = client.agents.auth.invocations.submit('invocation_id', { + field_values: { email: 'user@example.com', password: '********' }, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('submit: required and optional params', async () => { + const response = await client.agents.auth.invocations.submit('invocation_id', { + field_values: { email: 'user@example.com', password: '********' }, + }); + }); +}); From 8ccaae1b63ee9ca371c4f32033486e6e9ba1c351 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 03:45:26 +0000 Subject: [PATCH 04/10] fix(mcp): return correct lines on typescript errors --- .devcontainer/Dockerfile | 23 +++++++++++++++++++++++ .eslintrc.js | 10 ++++++++++ jest.setup.ts | 0 src/internal/polyfill/file.node.d.ts | 14 ++++++++++++++ src/internal/polyfill/file.node.mjs | 9 +++++++++ tests/responses.test.ts | 24 ++++++++++++++++++++++++ 6 files changed, 80 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .eslintrc.js create mode 100644 jest.setup.ts create mode 100644 src/internal/polyfill/file.node.d.ts create mode 100644 src/internal/polyfill/file.node.mjs create mode 100644 tests/responses.test.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..8ea34be --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:1 +FROM debian:bookworm-slim AS stainless + +RUN apt-get update && apt-get install -y \ + nodejs \ + npm \ + yarnpkg \ + && apt-get clean autoclean + +# Ensure UTF-8 encoding +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +# Yarn +RUN ln -sf /usr/bin/yarnpkg /usr/bin/yarn + +WORKDIR /workspace + +COPY package.json yarn.lock /workspace/ + +RUN yarn install + +COPY . /workspace diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..60f0e7a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], + rules: { + 'no-unused-vars': 'off', + 'prettier/prettier': 'error', + 'unused-imports/no-unused-imports': 'error', + }, + root: true, +}; diff --git a/jest.setup.ts b/jest.setup.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/internal/polyfill/file.node.d.ts b/src/internal/polyfill/file.node.d.ts new file mode 100644 index 0000000..c95276d --- /dev/null +++ b/src/internal/polyfill/file.node.d.ts @@ -0,0 +1,14 @@ +/** + * This file polyfills the global `File` object for you if it's not already defined + * when running on Node.js + * + * This is only needed on Node.js v18 & v19. Newer versions already define `File` + * as a global. + */ + +// @ts-ignore +type nodeBuffer = typeof import('node:buffer'); +declare const File: typeof globalThis extends { File: unknown } ? (typeof globalThis)['File'] +: nodeBuffer extends { File: unknown } ? nodeBuffer['File'] +: any; +export {}; diff --git a/src/internal/polyfill/file.node.mjs b/src/internal/polyfill/file.node.mjs new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/src/internal/polyfill/file.node.mjs @@ -0,0 +1,9 @@ +/** + * This file polyfills the global `File` object for you if it's not already defined + * when running on Node.js + * + * This is only needed on Node.js v18 & v19. Newer versions already define `File` + * as a global. + */ + +import './file.node.js'; diff --git a/tests/responses.test.ts b/tests/responses.test.ts new file mode 100644 index 0000000..7d08ea0 --- /dev/null +++ b/tests/responses.test.ts @@ -0,0 +1,24 @@ +import { createResponseHeaders } from '@onkernel/sdk/internal/headers'; + +describe('response parsing', () => { + // TODO: test unicode characters + test('headers are case agnostic', async () => { + const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); + expect(headers['content-type']).toEqual('foo'); + expect(headers['Content-type']).toEqual('foo'); + expect(headers['Content-Type']).toEqual('foo'); + expect(headers['accept']).toEqual('text/plain'); + expect(headers['Accept']).toEqual('text/plain'); + expect(headers['Hello-World']).toBeUndefined(); + }); + + test('duplicate headers are concatenated', () => { + const headers = createResponseHeaders( + new Headers([ + ['Content-Type', 'text/xml'], + ['Content-Type', 'application/json'], + ]), + ); + expect(headers['content-type']).toBe('text/xml, application/json'); + }); +}); From c9461e7e02592559c3592f8916bf1351d32cce9a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 03:46:16 +0000 Subject: [PATCH 05/10] chore(internal): codegen related update --- .devcontainer/Dockerfile | 23 ----------------------- .eslintrc.js | 10 ---------- jest.setup.ts | 0 src/internal/polyfill/file.node.d.ts | 14 -------------- src/internal/polyfill/file.node.mjs | 9 --------- tests/responses.test.ts | 24 ------------------------ 6 files changed, 80 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .eslintrc.js delete mode 100644 jest.setup.ts delete mode 100644 src/internal/polyfill/file.node.d.ts delete mode 100644 src/internal/polyfill/file.node.mjs delete mode 100644 tests/responses.test.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 8ea34be..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# syntax=docker/dockerfile:1 -FROM debian:bookworm-slim AS stainless - -RUN apt-get update && apt-get install -y \ - nodejs \ - npm \ - yarnpkg \ - && apt-get clean autoclean - -# Ensure UTF-8 encoding -ENV LANG=C.UTF-8 -ENV LC_ALL=C.UTF-8 - -# Yarn -RUN ln -sf /usr/bin/yarnpkg /usr/bin/yarn - -WORKDIR /workspace - -COPY package.json yarn.lock /workspace/ - -RUN yarn install - -COPY . /workspace diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 60f0e7a..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], - rules: { - 'no-unused-vars': 'off', - 'prettier/prettier': 'error', - 'unused-imports/no-unused-imports': 'error', - }, - root: true, -}; diff --git a/jest.setup.ts b/jest.setup.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/internal/polyfill/file.node.d.ts b/src/internal/polyfill/file.node.d.ts deleted file mode 100644 index c95276d..0000000 --- a/src/internal/polyfill/file.node.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file polyfills the global `File` object for you if it's not already defined - * when running on Node.js - * - * This is only needed on Node.js v18 & v19. Newer versions already define `File` - * as a global. - */ - -// @ts-ignore -type nodeBuffer = typeof import('node:buffer'); -declare const File: typeof globalThis extends { File: unknown } ? (typeof globalThis)['File'] -: nodeBuffer extends { File: unknown } ? nodeBuffer['File'] -: any; -export {}; diff --git a/src/internal/polyfill/file.node.mjs b/src/internal/polyfill/file.node.mjs deleted file mode 100644 index 520dcb8..0000000 --- a/src/internal/polyfill/file.node.mjs +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This file polyfills the global `File` object for you if it's not already defined - * when running on Node.js - * - * This is only needed on Node.js v18 & v19. Newer versions already define `File` - * as a global. - */ - -import './file.node.js'; diff --git a/tests/responses.test.ts b/tests/responses.test.ts deleted file mode 100644 index 7d08ea0..0000000 --- a/tests/responses.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createResponseHeaders } from '@onkernel/sdk/internal/headers'; - -describe('response parsing', () => { - // TODO: test unicode characters - test('headers are case agnostic', async () => { - const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); - expect(headers['content-type']).toEqual('foo'); - expect(headers['Content-type']).toEqual('foo'); - expect(headers['Content-Type']).toEqual('foo'); - expect(headers['accept']).toEqual('text/plain'); - expect(headers['Accept']).toEqual('text/plain'); - expect(headers['Hello-World']).toBeUndefined(); - }); - - test('duplicate headers are concatenated', () => { - const headers = createResponseHeaders( - new Headers([ - ['Content-Type', 'text/xml'], - ['Content-Type', 'application/json'], - ]), - ); - expect(headers['content-type']).toBe('text/xml, application/json'); - }); -}); From 4f6092702503c6dafb0d310c8123bf8dccce60e1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 03:47:13 +0000 Subject: [PATCH 06/10] fix(mcp): correct code tool API endpoint --- .devcontainer/Dockerfile | 23 +++++++++++++++++++++++ .eslintrc.js | 10 ++++++++++ jest.setup.ts | 0 src/internal/polyfill/file.node.d.ts | 14 ++++++++++++++ src/internal/polyfill/file.node.mjs | 9 +++++++++ tests/responses.test.ts | 24 ++++++++++++++++++++++++ 6 files changed, 80 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .eslintrc.js create mode 100644 jest.setup.ts create mode 100644 src/internal/polyfill/file.node.d.ts create mode 100644 src/internal/polyfill/file.node.mjs create mode 100644 tests/responses.test.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..8ea34be --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:1 +FROM debian:bookworm-slim AS stainless + +RUN apt-get update && apt-get install -y \ + nodejs \ + npm \ + yarnpkg \ + && apt-get clean autoclean + +# Ensure UTF-8 encoding +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +# Yarn +RUN ln -sf /usr/bin/yarnpkg /usr/bin/yarn + +WORKDIR /workspace + +COPY package.json yarn.lock /workspace/ + +RUN yarn install + +COPY . /workspace diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..60f0e7a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], + rules: { + 'no-unused-vars': 'off', + 'prettier/prettier': 'error', + 'unused-imports/no-unused-imports': 'error', + }, + root: true, +}; diff --git a/jest.setup.ts b/jest.setup.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/internal/polyfill/file.node.d.ts b/src/internal/polyfill/file.node.d.ts new file mode 100644 index 0000000..c95276d --- /dev/null +++ b/src/internal/polyfill/file.node.d.ts @@ -0,0 +1,14 @@ +/** + * This file polyfills the global `File` object for you if it's not already defined + * when running on Node.js + * + * This is only needed on Node.js v18 & v19. Newer versions already define `File` + * as a global. + */ + +// @ts-ignore +type nodeBuffer = typeof import('node:buffer'); +declare const File: typeof globalThis extends { File: unknown } ? (typeof globalThis)['File'] +: nodeBuffer extends { File: unknown } ? nodeBuffer['File'] +: any; +export {}; diff --git a/src/internal/polyfill/file.node.mjs b/src/internal/polyfill/file.node.mjs new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/src/internal/polyfill/file.node.mjs @@ -0,0 +1,9 @@ +/** + * This file polyfills the global `File` object for you if it's not already defined + * when running on Node.js + * + * This is only needed on Node.js v18 & v19. Newer versions already define `File` + * as a global. + */ + +import './file.node.js'; diff --git a/tests/responses.test.ts b/tests/responses.test.ts new file mode 100644 index 0000000..7d08ea0 --- /dev/null +++ b/tests/responses.test.ts @@ -0,0 +1,24 @@ +import { createResponseHeaders } from '@onkernel/sdk/internal/headers'; + +describe('response parsing', () => { + // TODO: test unicode characters + test('headers are case agnostic', async () => { + const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); + expect(headers['content-type']).toEqual('foo'); + expect(headers['Content-type']).toEqual('foo'); + expect(headers['Content-Type']).toEqual('foo'); + expect(headers['accept']).toEqual('text/plain'); + expect(headers['Accept']).toEqual('text/plain'); + expect(headers['Hello-World']).toBeUndefined(); + }); + + test('duplicate headers are concatenated', () => { + const headers = createResponseHeaders( + new Headers([ + ['Content-Type', 'text/xml'], + ['Content-Type', 'application/json'], + ]), + ); + expect(headers['content-type']).toBe('text/xml, application/json'); + }); +}); From 3ffeaa72b3cb5c7cd5baea0ddeaf5fad60979235 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 03:47:53 +0000 Subject: [PATCH 07/10] chore(internal): codegen related update --- .devcontainer/Dockerfile | 23 ----------------------- .eslintrc.js | 10 ---------- jest.setup.ts | 0 src/internal/polyfill/file.node.d.ts | 14 -------------- src/internal/polyfill/file.node.mjs | 9 --------- tests/responses.test.ts | 24 ------------------------ 6 files changed, 80 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .eslintrc.js delete mode 100644 jest.setup.ts delete mode 100644 src/internal/polyfill/file.node.d.ts delete mode 100644 src/internal/polyfill/file.node.mjs delete mode 100644 tests/responses.test.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 8ea34be..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# syntax=docker/dockerfile:1 -FROM debian:bookworm-slim AS stainless - -RUN apt-get update && apt-get install -y \ - nodejs \ - npm \ - yarnpkg \ - && apt-get clean autoclean - -# Ensure UTF-8 encoding -ENV LANG=C.UTF-8 -ENV LC_ALL=C.UTF-8 - -# Yarn -RUN ln -sf /usr/bin/yarnpkg /usr/bin/yarn - -WORKDIR /workspace - -COPY package.json yarn.lock /workspace/ - -RUN yarn install - -COPY . /workspace diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 60f0e7a..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], - rules: { - 'no-unused-vars': 'off', - 'prettier/prettier': 'error', - 'unused-imports/no-unused-imports': 'error', - }, - root: true, -}; diff --git a/jest.setup.ts b/jest.setup.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/internal/polyfill/file.node.d.ts b/src/internal/polyfill/file.node.d.ts deleted file mode 100644 index c95276d..0000000 --- a/src/internal/polyfill/file.node.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file polyfills the global `File` object for you if it's not already defined - * when running on Node.js - * - * This is only needed on Node.js v18 & v19. Newer versions already define `File` - * as a global. - */ - -// @ts-ignore -type nodeBuffer = typeof import('node:buffer'); -declare const File: typeof globalThis extends { File: unknown } ? (typeof globalThis)['File'] -: nodeBuffer extends { File: unknown } ? nodeBuffer['File'] -: any; -export {}; diff --git a/src/internal/polyfill/file.node.mjs b/src/internal/polyfill/file.node.mjs deleted file mode 100644 index 520dcb8..0000000 --- a/src/internal/polyfill/file.node.mjs +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This file polyfills the global `File` object for you if it's not already defined - * when running on Node.js - * - * This is only needed on Node.js v18 & v19. Newer versions already define `File` - * as a global. - */ - -import './file.node.js'; diff --git a/tests/responses.test.ts b/tests/responses.test.ts deleted file mode 100644 index 7d08ea0..0000000 --- a/tests/responses.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createResponseHeaders } from '@onkernel/sdk/internal/headers'; - -describe('response parsing', () => { - // TODO: test unicode characters - test('headers are case agnostic', async () => { - const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); - expect(headers['content-type']).toEqual('foo'); - expect(headers['Content-type']).toEqual('foo'); - expect(headers['Content-Type']).toEqual('foo'); - expect(headers['accept']).toEqual('text/plain'); - expect(headers['Accept']).toEqual('text/plain'); - expect(headers['Hello-World']).toBeUndefined(); - }); - - test('duplicate headers are concatenated', () => { - const headers = createResponseHeaders( - new Headers([ - ['Content-Type', 'text/xml'], - ['Content-Type', 'application/json'], - ]), - ); - expect(headers['content-type']).toBe('text/xml, application/json'); - }); -}); From 0ef28fddbf7c7d03b24a56d4157d1eb3966c0a7f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 06:55:43 +0000 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20enhance=20agent=20authentication?= =?UTF-8?q?=20API=20with=20new=20endpoints=20and=20request=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stats.yml | 8 +- api.md | 8 +- src/resources/agents/agents.ts | 16 +- src/resources/agents/auth/auth.ts | 181 +++++++++++++----- src/resources/agents/auth/index.ts | 9 +- src/resources/agents/auth/invocations.ts | 28 +++ src/resources/agents/index.ts | 8 +- tests/api-resources/agents/auth/auth.test.ts | 48 +++-- .../agents/auth/invocations.test.ts | 17 ++ 9 files changed, 244 insertions(+), 79 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0c474bb..4bf353a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 80 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8a37652fa586b8932466d16285359a89988505f850787f8257d0c4c7053da173.yml -openapi_spec_hash: 042765a113f6d08109e8146b302323ec -config_hash: 113f1e5bc3567628a5d51c70bc00969d +configured_endpoints: 82 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b6957db438b01d979b62de21d4e674601b37d55b850b95a6e2b4c771aad5e840.yml +openapi_spec_hash: 1c8aac8322bc9df8f1b82a7e7a0c692b +config_hash: a4b4d14bdf6af723b235a6981977627c diff --git a/api.md b/api.md index 6d64516..2050a8d 100644 --- a/api.md +++ b/api.md @@ -255,15 +255,18 @@ Types: - AgentAuthDiscoverResponse - AgentAuthInvocationResponse -- AgentAuthStartResponse - AgentAuthSubmitResponse - AuthAgent +- AuthAgentCreateRequest +- AuthAgentInvocationCreateRequest +- AuthAgentInvocationCreateResponse - DiscoveredField Methods: +- client.agents.auth.create({ ...params }) -> AuthAgent - client.agents.auth.retrieve(id) -> AuthAgent -- client.agents.auth.start({ ...params }) -> AgentAuthStartResponse +- client.agents.auth.list({ ...params }) -> AuthAgentsOffsetPagination ### Invocations @@ -273,6 +276,7 @@ Types: Methods: +- client.agents.auth.invocations.create({ ...params }) -> AuthAgentInvocationCreateResponse - client.agents.auth.invocations.retrieve(invocationID) -> AgentAuthInvocationResponse - client.agents.auth.invocations.discover(invocationID, { ...params }) -> AgentAuthDiscoverResponse - client.agents.auth.invocations.exchange(invocationID, { ...params }) -> InvocationExchangeResponse diff --git a/src/resources/agents/agents.ts b/src/resources/agents/agents.ts index 5155028..cf10a25 100644 --- a/src/resources/agents/agents.ts +++ b/src/resources/agents/agents.ts @@ -5,11 +5,15 @@ import * as AuthAPI from './auth/auth'; import { AgentAuthDiscoverResponse, AgentAuthInvocationResponse, - AgentAuthStartResponse, AgentAuthSubmitResponse, Auth, AuthAgent, - AuthStartParams, + AuthAgentCreateRequest, + AuthAgentInvocationCreateRequest, + AuthAgentInvocationCreateResponse, + AuthAgentsOffsetPagination, + AuthCreateParams, + AuthListParams, DiscoveredField, } from './auth/auth'; @@ -24,10 +28,14 @@ export declare namespace Agents { Auth as Auth, type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, type AgentAuthInvocationResponse as AgentAuthInvocationResponse, - type AgentAuthStartResponse as AgentAuthStartResponse, type AgentAuthSubmitResponse as AgentAuthSubmitResponse, type AuthAgent as AuthAgent, + type AuthAgentCreateRequest as AuthAgentCreateRequest, + type AuthAgentInvocationCreateRequest as AuthAgentInvocationCreateRequest, + type AuthAgentInvocationCreateResponse as AuthAgentInvocationCreateResponse, type DiscoveredField as DiscoveredField, - type AuthStartParams as AuthStartParams, + type AuthAgentsOffsetPagination as AuthAgentsOffsetPagination, + type AuthCreateParams as AuthCreateParams, + type AuthListParams as AuthListParams, }; } diff --git a/src/resources/agents/auth/auth.ts b/src/resources/agents/auth/auth.ts index 65d847e..2ece2e2 100644 --- a/src/resources/agents/auth/auth.ts +++ b/src/resources/agents/auth/auth.ts @@ -3,6 +3,7 @@ import { APIResource } from '../../../core/resource'; import * as InvocationsAPI from './invocations'; import { + InvocationCreateParams, InvocationDiscoverParams, InvocationExchangeParams, InvocationExchangeResponse, @@ -10,12 +11,31 @@ import { Invocations, } from './invocations'; import { APIPromise } from '../../../core/api-promise'; +import { OffsetPagination, type OffsetPaginationParams, PagePromise } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; import { path } from '../../../internal/utils/path'; export class Auth extends APIResource { invocations: InvocationsAPI.Invocations = new InvocationsAPI.Invocations(this._client); + /** + * Creates a new auth agent for the specified domain and profile combination, or + * returns an existing one if it already exists. This is idempotent - calling with + * the same domain and profile will return the same agent. Does NOT start an + * invocation - use POST /agents/auth/invocations to start an auth flow. + * + * @example + * ```ts + * const authAgent = await client.agents.auth.create({ + * profile_name: 'user-123', + * target_domain: 'netflix.com', + * }); + * ``` + */ + create(body: AuthCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/agents/auth', { body, ...options }); + } + /** * Retrieve an auth agent by its ID. Returns the current authentication status of * the managed profile. @@ -30,24 +50,26 @@ export class Auth extends APIResource { } /** - * Creates a browser session and returns a handoff code for the hosted flow. Uses - * standard API key or JWT authentication (not the JWT returned by the exchange - * endpoint). + * List auth agents with optional filters for profile_name and target_domain. * * @example * ```ts - * const agentAuthStartResponse = - * await client.agents.auth.start({ - * profile_name: 'auth-abc123', - * target_domain: 'doordash.com', - * }); + * // Automatically fetches more pages as needed. + * for await (const authAgent of client.agents.auth.list()) { + * // ... + * } * ``` */ - start(body: AuthStartParams, options?: RequestOptions): APIPromise { - return this._client.post('/agents/auth/start', { body, ...options }); + list( + query: AuthListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/agents/auth', OffsetPagination, { query, ...options }); } } +export type AuthAgentsOffsetPagination = OffsetPagination; + /** * Response from discover endpoint matching AuthBlueprint schema */ @@ -108,36 +130,6 @@ export interface AgentAuthInvocationResponse { target_domain: string; } -/** - * Response from starting an agent authentication invocation - */ -export interface AgentAuthStartResponse { - /** - * Unique identifier for the auth agent managing this domain/profile - */ - auth_agent_id: string; - - /** - * When the handoff code expires - */ - expires_at: string; - - /** - * One-time code for handoff - */ - handoff_code: string; - - /** - * URL to redirect user to - */ - hosted_url: string; - - /** - * Unique identifier for the invocation - */ - invocation_id: string; -} - /** * Response from submit endpoint matching SubmitResult schema */ @@ -205,6 +197,79 @@ export interface AuthAgent { status: 'AUTHENTICATED' | 'NEEDS_AUTH'; } +/** + * Request to create or find an auth agent + */ +export interface AuthAgentCreateRequest { + /** + * Name of the profile to use for this auth agent + */ + profile_name: string; + + /** + * Target domain for authentication + */ + target_domain: string; + + /** + * Optional login page URL. If provided, will be stored on the agent and used to + * skip discovery in future invocations. + */ + login_url?: string; + + /** + * Optional proxy configuration + */ + proxy?: AuthAgentCreateRequest.Proxy; +} + +export namespace AuthAgentCreateRequest { + /** + * Optional proxy configuration + */ + export interface Proxy { + /** + * ID of the proxy to use + */ + proxy_id?: string; + } +} + +/** + * Request to create an invocation for an existing auth agent + */ +export interface AuthAgentInvocationCreateRequest { + /** + * ID of the auth agent to create an invocation for + */ + auth_agent_id: string; +} + +/** + * Response from creating an auth agent invocation + */ +export interface AuthAgentInvocationCreateResponse { + /** + * When the handoff code expires + */ + expires_at: string; + + /** + * One-time code for handoff + */ + handoff_code: string; + + /** + * URL to redirect user to + */ + hosted_url: string; + + /** + * Unique identifier for the invocation + */ + invocation_id: string; +} + /** * A discovered form field */ @@ -240,9 +305,9 @@ export interface DiscoveredField { required?: boolean; } -export interface AuthStartParams { +export interface AuthCreateParams { /** - * Name of the profile to use for this flow + * Name of the profile to use for this auth agent */ profile_name: string; @@ -251,24 +316,19 @@ export interface AuthStartParams { */ target_domain: string; - /** - * Optional logo URL for the application - */ - app_logo_url?: string; - /** * Optional login page URL. If provided, will be stored on the agent and used to - * skip Phase 1 discovery in future invocations. + * skip discovery in future invocations. */ login_url?: string; /** * Optional proxy configuration */ - proxy?: AuthStartParams.Proxy; + proxy?: AuthCreateParams.Proxy; } -export namespace AuthStartParams { +export namespace AuthCreateParams { /** * Optional proxy configuration */ @@ -280,22 +340,39 @@ export namespace AuthStartParams { } } +export interface AuthListParams extends OffsetPaginationParams { + /** + * Filter by profile name + */ + profile_name?: string; + + /** + * Filter by target domain + */ + target_domain?: string; +} + Auth.Invocations = Invocations; export declare namespace Auth { export { type AgentAuthDiscoverResponse as AgentAuthDiscoverResponse, type AgentAuthInvocationResponse as AgentAuthInvocationResponse, - type AgentAuthStartResponse as AgentAuthStartResponse, type AgentAuthSubmitResponse as AgentAuthSubmitResponse, type AuthAgent as AuthAgent, + type AuthAgentCreateRequest as AuthAgentCreateRequest, + type AuthAgentInvocationCreateRequest as AuthAgentInvocationCreateRequest, + type AuthAgentInvocationCreateResponse as AuthAgentInvocationCreateResponse, type DiscoveredField as DiscoveredField, - type AuthStartParams as AuthStartParams, + type AuthAgentsOffsetPagination as AuthAgentsOffsetPagination, + type AuthCreateParams as AuthCreateParams, + type AuthListParams as AuthListParams, }; export { Invocations as Invocations, type InvocationExchangeResponse as InvocationExchangeResponse, + type InvocationCreateParams as InvocationCreateParams, type InvocationDiscoverParams as InvocationDiscoverParams, type InvocationExchangeParams as InvocationExchangeParams, type InvocationSubmitParams as InvocationSubmitParams, diff --git a/src/resources/agents/auth/index.ts b/src/resources/agents/auth/index.ts index b364643..e0a4170 100644 --- a/src/resources/agents/auth/index.ts +++ b/src/resources/agents/auth/index.ts @@ -4,15 +4,20 @@ export { Auth, type AgentAuthDiscoverResponse, type AgentAuthInvocationResponse, - type AgentAuthStartResponse, type AgentAuthSubmitResponse, type AuthAgent, + type AuthAgentCreateRequest, + type AuthAgentInvocationCreateRequest, + type AuthAgentInvocationCreateResponse, type DiscoveredField, - type AuthStartParams, + type AuthCreateParams, + type AuthListParams, + type AuthAgentsOffsetPagination, } from './auth'; export { Invocations, type InvocationExchangeResponse, + type InvocationCreateParams, type InvocationDiscoverParams, type InvocationExchangeParams, type InvocationSubmitParams, diff --git a/src/resources/agents/auth/invocations.ts b/src/resources/agents/auth/invocations.ts index 4c87d5d..47dc460 100644 --- a/src/resources/agents/auth/invocations.ts +++ b/src/resources/agents/auth/invocations.ts @@ -7,6 +7,26 @@ import { RequestOptions } from '../../../internal/request-options'; import { path } from '../../../internal/utils/path'; export class Invocations extends APIResource { + /** + * Creates a new authentication invocation for the specified auth agent. This + * starts the auth flow and returns a hosted URL for the user to complete + * authentication. + * + * @example + * ```ts + * const authAgentInvocationCreateResponse = + * await client.agents.auth.invocations.create({ + * auth_agent_id: 'abc123xyz', + * }); + * ``` + */ + create( + body: InvocationCreateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/agents/auth/invocations', { body, ...options }); + } + /** * Returns invocation details including app_name and target_domain. Uses the JWT * returned by the exchange endpoint, or standard API key or JWT authentication. @@ -107,6 +127,13 @@ export interface InvocationExchangeResponse { jwt: string; } +export interface InvocationCreateParams { + /** + * ID of the auth agent to create an invocation for + */ + auth_agent_id: string; +} + export interface InvocationDiscoverParams { /** * Optional login page URL. If provided, will override the stored login URL for @@ -132,6 +159,7 @@ export interface InvocationSubmitParams { export declare namespace Invocations { export { type InvocationExchangeResponse as InvocationExchangeResponse, + type InvocationCreateParams as InvocationCreateParams, type InvocationDiscoverParams as InvocationDiscoverParams, type InvocationExchangeParams as InvocationExchangeParams, type InvocationSubmitParams as InvocationSubmitParams, diff --git a/src/resources/agents/index.ts b/src/resources/agents/index.ts index 86baf26..4d4ea82 100644 --- a/src/resources/agents/index.ts +++ b/src/resources/agents/index.ts @@ -5,9 +5,13 @@ export { Auth, type AgentAuthDiscoverResponse, type AgentAuthInvocationResponse, - type AgentAuthStartResponse, type AgentAuthSubmitResponse, type AuthAgent, + type AuthAgentCreateRequest, + type AuthAgentInvocationCreateRequest, + type AuthAgentInvocationCreateResponse, type DiscoveredField, - type AuthStartParams, + type AuthCreateParams, + type AuthListParams, + type AuthAgentsOffsetPagination, } from './auth/index'; diff --git a/tests/api-resources/agents/auth/auth.test.ts b/tests/api-resources/agents/auth/auth.test.ts index d0007db..a51a775 100644 --- a/tests/api-resources/agents/auth/auth.test.ts +++ b/tests/api-resources/agents/auth/auth.test.ts @@ -8,6 +8,31 @@ const client = new Kernel({ }); describe('resource auth', () => { + // Prism tests are disabled + test.skip('create: only required params', async () => { + const responsePromise = client.agents.auth.create({ + profile_name: 'user-123', + target_domain: 'netflix.com', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('create: required and optional params', async () => { + const response = await client.agents.auth.create({ + profile_name: 'user-123', + target_domain: 'netflix.com', + login_url: 'https://netflix.com/login', + proxy: { proxy_id: 'proxy_id' }, + }); + }); + // Prism tests are disabled test.skip('retrieve', async () => { const responsePromise = client.agents.auth.retrieve('id'); @@ -21,11 +46,8 @@ describe('resource auth', () => { }); // Prism tests are disabled - test.skip('start: only required params', async () => { - const responsePromise = client.agents.auth.start({ - profile_name: 'auth-abc123', - target_domain: 'doordash.com', - }); + test.skip('list', async () => { + const responsePromise = client.agents.auth.list(); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -36,13 +58,13 @@ describe('resource auth', () => { }); // Prism tests are disabled - test.skip('start: required and optional params', async () => { - const response = await client.agents.auth.start({ - profile_name: 'auth-abc123', - target_domain: 'doordash.com', - app_logo_url: 'https://example.com/logo.png', - login_url: 'https://doordash.com/account/login', - proxy: { proxy_id: 'proxy_id' }, - }); + test.skip('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.agents.auth.list( + { limit: 100, offset: 0, profile_name: 'profile_name', target_domain: 'target_domain' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Kernel.NotFoundError); }); }); diff --git a/tests/api-resources/agents/auth/invocations.test.ts b/tests/api-resources/agents/auth/invocations.test.ts index 33a58f9..8bc769c 100644 --- a/tests/api-resources/agents/auth/invocations.test.ts +++ b/tests/api-resources/agents/auth/invocations.test.ts @@ -8,6 +8,23 @@ const client = new Kernel({ }); describe('resource invocations', () => { + // Prism tests are disabled + test.skip('create: only required params', async () => { + const responsePromise = client.agents.auth.invocations.create({ auth_agent_id: 'abc123xyz' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism tests are disabled + test.skip('create: required and optional params', async () => { + const response = await client.agents.auth.invocations.create({ auth_agent_id: 'abc123xyz' }); + }); + // Prism tests are disabled test.skip('retrieve', async () => { const responsePromise = client.agents.auth.invocations.retrieve('invocation_id'); From 29d43d10a026f25cf1a1de2579c06f90ca246054 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 19:34:57 +0000 Subject: [PATCH 09/10] feat: Enhance AuthAgent model with last_auth_check_at field --- .stats.yml | 4 ++-- src/resources/agents/auth/auth.ts | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4bf353a..135345a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 82 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b6957db438b01d979b62de21d4e674601b37d55b850b95a6e2b4c771aad5e840.yml -openapi_spec_hash: 1c8aac8322bc9df8f1b82a7e7a0c692b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-dac11bdb857e700a8c39d183e753ddd1ebaaca69fd9fc5ee57d6b56b70b00e6e.yml +openapi_spec_hash: 78fbc50dd0b61cdc87564fbea278ee23 config_hash: a4b4d14bdf6af723b235a6981977627c diff --git a/src/resources/agents/auth/auth.ts b/src/resources/agents/auth/auth.ts index 2ece2e2..ca02544 100644 --- a/src/resources/agents/auth/auth.ts +++ b/src/resources/agents/auth/auth.ts @@ -195,6 +195,11 @@ export interface AuthAgent { * Current authentication status of the managed profile */ status: 'AUTHENTICATED' | 'NEEDS_AUTH'; + + /** + * When the last authentication check was performed + */ + last_auth_check_at?: string; } /** From 689c61df58d7b38b1ffd00bfcbaac0af2987d00a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 19:35:19 +0000 Subject: [PATCH 10/10] release: 0.23.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ package.json | 2 +- src/version.ts | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 788b0fa..97bce11 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.22.0" + ".": "0.23.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f50be4..b5a1736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## 0.23.0 (2025-12-11) + +Full Changelog: [v0.22.0...v0.23.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.22.0...v0.23.0) + +### Features + +* [wip] Browser pools polish pass ([7c8a464](https://github.com/onkernel/kernel-node-sdk/commit/7c8a4641cb87a76a3248e2d1df713df929957262)) +* enhance agent authentication API with new endpoints and request… ([0ef28fd](https://github.com/onkernel/kernel-node-sdk/commit/0ef28fddbf7c7d03b24a56d4157d1eb3966c0a7f)) +* Enhance agent authentication with optional login page URL and auth ch… ([7ea4b07](https://github.com/onkernel/kernel-node-sdk/commit/7ea4b076cc5255f76945ae370a8f686349a28a30)) +* Enhance AuthAgent model with last_auth_check_at field ([29d43d1](https://github.com/onkernel/kernel-node-sdk/commit/29d43d10a026f25cf1a1de2579c06f90ca246054)) + + +### Bug Fixes + +* **mcp:** correct code tool API endpoint ([4f60927](https://github.com/onkernel/kernel-node-sdk/commit/4f6092702503c6dafb0d310c8123bf8dccce60e1)) +* **mcp:** return correct lines on typescript errors ([8ccaae1](https://github.com/onkernel/kernel-node-sdk/commit/8ccaae1b63ee9ca371c4f32033486e6e9ba1c351)) + + +### Chores + +* **internal:** codegen related update ([3ffeaa7](https://github.com/onkernel/kernel-node-sdk/commit/3ffeaa72b3cb5c7cd5baea0ddeaf5fad60979235)) +* **internal:** codegen related update ([c9461e7](https://github.com/onkernel/kernel-node-sdk/commit/c9461e7e02592559c3592f8916bf1351d32cce9a)) + + +### Refactors + +* **browser:** remove persistence option UI ([f3fdc89](https://github.com/onkernel/kernel-node-sdk/commit/f3fdc89088feeb32983da39700e47e922f767126)) + ## 0.22.0 (2025-12-05) Full Changelog: [v0.21.0...v0.22.0](https://github.com/onkernel/kernel-node-sdk/compare/v0.21.0...v0.22.0) diff --git a/package.json b/package.json index 76cf5a4..5383c20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onkernel/sdk", - "version": "0.22.0", + "version": "0.23.0", "description": "The official TypeScript library for the Kernel API", "author": "Kernel <>", "types": "dist/index.d.ts", diff --git a/src/version.ts b/src/version.ts index db66d33..d77fad4 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.22.0'; // x-release-please-version +export const VERSION = '0.23.0'; // x-release-please-version