From aa0408c0867f3448ef2155541fb67966ccfc6e21 Mon Sep 17 00:00:00 2001 From: "madison.packer" Date: Fri, 28 Aug 2026 18:56:07 +0000 Subject: [PATCH] Add Agent Blueprints API support Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- src/agents/agents.spec.ts | 421 ++++++++++++++++++ src/agents/agents.ts | 323 ++++++++++++++ src/agents/fixtures/get-agent-blueprint.json | 18 + .../fixtures/get-agent-instance-session.json | 10 + src/agents/fixtures/get-agent-instance.json | 10 + .../fixtures/list-agent-blueprints.json | 27 ++ .../list-agent-instance-sessions.json | 19 + src/agents/fixtures/list-agent-instances.json | 19 + src/agents/fixtures/mint-agent-token.json | 10 + .../interfaces/agent-blueprint.interface.ts | 160 +++++++ .../agent-instance-session.interface.ts | 47 ++ .../interfaces/agent-instance.interface.ts | 50 +++ .../interfaces/agent-token.interface.ts | 94 ++++ src/agents/interfaces/index.ts | 4 + .../serializers/agent-blueprint.serializer.ts | 101 +++++ .../agent-instance-session.serializer.ts | 34 ++ .../serializers/agent-instance.serializer.ts | 34 ++ .../serializers/agent-token.serializer.ts | 52 +++ src/agents/serializers/index.ts | 4 + 19 files changed, 1437 insertions(+) create mode 100644 src/agents/fixtures/get-agent-blueprint.json create mode 100644 src/agents/fixtures/get-agent-instance-session.json create mode 100644 src/agents/fixtures/get-agent-instance.json create mode 100644 src/agents/fixtures/list-agent-blueprints.json create mode 100644 src/agents/fixtures/list-agent-instance-sessions.json create mode 100644 src/agents/fixtures/list-agent-instances.json create mode 100644 src/agents/fixtures/mint-agent-token.json create mode 100644 src/agents/interfaces/agent-blueprint.interface.ts create mode 100644 src/agents/interfaces/agent-instance-session.interface.ts create mode 100644 src/agents/interfaces/agent-instance.interface.ts create mode 100644 src/agents/interfaces/agent-token.interface.ts create mode 100644 src/agents/serializers/agent-blueprint.serializer.ts create mode 100644 src/agents/serializers/agent-instance-session.serializer.ts create mode 100644 src/agents/serializers/agent-instance.serializer.ts create mode 100644 src/agents/serializers/agent-token.serializer.ts diff --git a/src/agents/agents.spec.ts b/src/agents/agents.spec.ts index db6c20acb..7e1129942 100644 --- a/src/agents/agents.spec.ts +++ b/src/agents/agents.spec.ts @@ -4,13 +4,40 @@ import { fetchBody, fetchMethod, fetchOnce, + fetchSearchParams, fetchURL, } from '../common/utils/test-utils'; import { WorkOS } from '../workos'; import createClaimAttemptFixture from './fixtures/create-claim-attempt.json'; +import getAgentBlueprintFixture from './fixtures/get-agent-blueprint.json'; +import getAgentInstanceFixture from './fixtures/get-agent-instance.json'; +import getAgentInstanceSessionFixture from './fixtures/get-agent-instance-session.json'; import getAgentRegistrationFixture from './fixtures/get-agent-registration.json'; +import listAgentBlueprintsFixture from './fixtures/list-agent-blueprints.json'; +import listAgentInstanceSessionsFixture from './fixtures/list-agent-instance-sessions.json'; +import listAgentInstancesFixture from './fixtures/list-agent-instances.json'; +import mintAgentTokenFixture from './fixtures/mint-agent-token.json'; import validateAgentCredentialFixture from './fixtures/validate-agent-credential.json'; +const EXPECTED_BLUEPRINT = { + object: 'agent_blueprint', + id: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + name: 'Prospecting Agent', + description: 'Finds and qualifies sales prospects.', + permissions: ['crm:read', 'email:send'], + invocableBy: { + roleSlugs: ['manager'], + organizationIds: ['org_01EHWNCE74X7JSDV0X3SZ3KJNY'], + }, + sessionSettings: { + maxAgeSeconds: 3600, + accessTokenTtlSeconds: 300, + refreshTokenTtlSeconds: 3600, + }, + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', +}; + jest.mock('jose', () => ({ ...jest.requireActual('jose'), jwtVerify: jest.fn(), @@ -455,4 +482,398 @@ describe('Agents', () => { }); }); }); + + describe('createBlueprint', () => { + it('sends the request and deserializes the response', async () => { + fetchOnce(getAgentBlueprintFixture, { status: 201 }); + + const blueprint = await workos.agents.createBlueprint({ + name: 'Prospecting Agent', + description: 'Finds and qualifies sales prospects.', + permissions: ['crm:read', 'email:send'], + invocableBy: { + roleSlugs: ['manager'], + organizationIds: ['org_01EHWNCE74X7JSDV0X3SZ3KJNY'], + }, + sessionSettings: { + maxAgeSeconds: 3600, + accessTokenTtlSeconds: 300, + refreshTokenTtlSeconds: 3600, + }, + }); + + expect(fetchURL()).toContain('/agents/blueprints'); + expect(fetchMethod()).toBe('POST'); + expect(fetchBody()).toEqual({ + name: 'Prospecting Agent', + description: 'Finds and qualifies sales prospects.', + permissions: ['crm:read', 'email:send'], + invocable_by: { + role_slugs: ['manager'], + organization_ids: ['org_01EHWNCE74X7JSDV0X3SZ3KJNY'], + }, + session_settings: { + max_age_seconds: 3600, + access_token_ttl_seconds: 300, + refresh_token_ttl_seconds: 3600, + }, + }); + expect(blueprint).toEqual(EXPECTED_BLUEPRINT); + }); + + it('omits optional fields that are not provided', async () => { + fetchOnce(getAgentBlueprintFixture, { status: 201 }); + + await workos.agents.createBlueprint({ + name: 'Prospecting Agent', + sessionSettings: { + maxAgeSeconds: 3600, + accessTokenTtlSeconds: 300, + refreshTokenTtlSeconds: 3600, + }, + }); + + expect(fetchBody()).toEqual({ + name: 'Prospecting Agent', + session_settings: { + max_age_seconds: 3600, + access_token_ttl_seconds: 300, + refresh_token_ttl_seconds: 3600, + }, + }); + }); + }); + + describe('listBlueprints', () => { + it('lists agent blueprints', async () => { + fetchOnce(listAgentBlueprintsFixture); + + const { data } = await workos.agents.listBlueprints(); + + expect(fetchURL()).toContain('/agents/blueprints'); + expect(fetchMethod()).toBe('GET'); + expect(data).toEqual([EXPECTED_BLUEPRINT]); + }); + + it('sends pagination options as query parameters', async () => { + fetchOnce(listAgentBlueprintsFixture); + + await workos.agents.listBlueprints({ + limit: 10, + after: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + order: 'asc', + }); + + expect(fetchSearchParams()).toEqual({ + limit: '10', + after: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + order: 'asc', + }); + }); + }); + + describe('getBlueprint', () => { + it('gets an agent blueprint by ID', async () => { + fetchOnce(getAgentBlueprintFixture); + + const blueprint = await workos.agents.getBlueprint( + 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/blueprints/agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('GET'); + expect(blueprint).toEqual(EXPECTED_BLUEPRINT); + }); + }); + + describe('updateBlueprint', () => { + it('sends only the provided fields', async () => { + fetchOnce(getAgentBlueprintFixture); + + const blueprint = await workos.agents.updateBlueprint({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + name: 'Prospecting Agent', + sessionSettings: { + accessTokenTtlSeconds: 300, + }, + }); + + expect(fetchURL()).toContain( + '/agents/blueprints/agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('PATCH'); + expect(fetchBody()).toEqual({ + name: 'Prospecting Agent', + session_settings: { + access_token_ttl_seconds: 300, + }, + }); + expect(blueprint).toEqual(EXPECTED_BLUEPRINT); + }); + + it('sends a null description to clear it', async () => { + fetchOnce(getAgentBlueprintFixture); + + await workos.agents.updateBlueprint({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + description: null, + }); + + expect(fetchBody()).toEqual({ description: null }); + }); + }); + + describe('deleteBlueprint', () => { + it('deletes an agent blueprint by ID', async () => { + fetchOnce(undefined, { status: 204 }); + + await workos.agents.deleteBlueprint( + 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/blueprints/agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('DELETE'); + }); + }); + + describe('mintToken', () => { + const expectedToken = { + accessToken: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.example.token', + tokenType: 'Bearer', + expiresIn: 300, + refreshToken: 'refresh_token_example', + agentInstanceId: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + newInstance: true, + agentInstanceSessionId: + 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + permissions: ['crm:read', 'email:send'], + }; + + it('mints a user-delegated token', async () => { + fetchOnce(mintAgentTokenFixture); + + const token = await workos.agents.mintToken({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + type: 'user_delegated', + userAccessToken: 'user_access_token_example', + intent: 'Prospect new leads', + }); + + expect(fetchURL()).toContain( + '/agents/blueprints/agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY/tokens', + ); + expect(fetchMethod()).toBe('POST'); + expect(fetchBody()).toEqual({ + type: 'user_delegated', + user_access_token: 'user_access_token_example', + intent: 'Prospect new leads', + }); + expect(token).toEqual(expectedToken); + }); + + it('mints an autonomous token', async () => { + fetchOnce(mintAgentTokenFixture); + + await workos.agents.mintToken({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + type: 'autonomous', + organizationId: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + }); + + expect(fetchBody()).toEqual({ + type: 'autonomous', + organization_id: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + }); + }); + + it('mints an agent-delegated token', async () => { + fetchOnce(mintAgentTokenFixture); + + await workos.agents.mintToken({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + type: 'agent_delegated', + agentAccessToken: 'agent_access_token_example', + }); + + expect(fetchBody()).toEqual({ + type: 'agent_delegated', + agent_access_token: 'agent_access_token_example', + }); + }); + + it('refreshes a token', async () => { + fetchOnce(mintAgentTokenFixture); + + await workos.agents.mintToken({ + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + type: 'refresh', + refreshToken: 'refresh_token_example', + }); + + expect(fetchBody()).toEqual({ + type: 'refresh', + refresh_token: 'refresh_token_example', + }); + }); + }); + + describe('listInstances', () => { + it('lists agent instances with filters', async () => { + fetchOnce(listAgentInstancesFixture); + + const { data } = await workos.agents.listInstances({ + organizationId: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + limit: 10, + }); + + expect(fetchURL()).toContain('/agents/instances'); + expect(fetchMethod()).toBe('GET'); + expect(fetchSearchParams()).toEqual({ + organization_id: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + agent_blueprint_id: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + limit: '10', + order: 'desc', + }); + expect(data).toEqual([ + { + object: 'agent_instance', + id: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + organizationId: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + organizationMembershipId: null, + type: 'autonomous', + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', + }, + ]); + }); + }); + + describe('getInstance', () => { + it('gets an agent instance by ID', async () => { + fetchOnce(getAgentInstanceFixture); + + const instance = await workos.agents.getInstance( + 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/instances/agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('GET'); + expect(instance).toEqual({ + object: 'agent_instance', + id: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentBlueprintId: 'agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY', + organizationId: 'org_01EHWNCE74X7JSDV0X3SZ3KJNY', + organizationMembershipId: 'om_01EHWNCE74X7JSDV0X3SZ3KJNY', + type: 'delegated', + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', + }); + }); + }); + + describe('deleteInstance', () => { + it('deletes an agent instance by ID', async () => { + fetchOnce(undefined, { status: 204 }); + + await workos.agents.deleteInstance( + 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/instances/agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('DELETE'); + }); + }); + + describe('listInstanceSessions', () => { + it('lists agent instance sessions with filters', async () => { + fetchOnce(listAgentInstanceSessionsFixture); + + const { data } = await workos.agents.listInstanceSessions({ + agentInstanceId: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + }); + + expect(fetchURL()).toContain('/agents/sessions'); + expect(fetchMethod()).toBe('GET'); + expect(fetchSearchParams()).toEqual({ + agent_instance_id: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + order: 'desc', + }); + expect(data).toEqual([ + { + object: 'agent_instance_session', + id: 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentInstanceId: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + status: 'active', + expiresAt: '2099-01-01T00:00:00.000Z', + revokedAt: null, + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', + }, + ]); + }); + }); + + describe('getInstanceSession', () => { + it('gets an agent instance session by ID', async () => { + fetchOnce(getAgentInstanceSessionFixture); + + const session = await workos.agents.getInstanceSession( + 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/sessions/agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + expect(fetchMethod()).toBe('GET'); + expect(session).toEqual({ + object: 'agent_instance_session', + id: 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentInstanceId: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + status: 'active', + expiresAt: '2099-01-01T00:00:00.000Z', + revokedAt: null, + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', + }); + }); + }); + + describe('revokeInstanceSession', () => { + it('revokes an agent instance session by ID', async () => { + fetchOnce({ + ...getAgentInstanceSessionFixture, + status: 'revoked', + revoked_at: '2023-07-18T02:08:00.000Z', + }); + + const session = await workos.agents.revokeInstanceSession( + 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + ); + + expect(fetchURL()).toContain( + '/agents/sessions/agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY/revoke', + ); + expect(fetchMethod()).toBe('POST'); + expect(session).toEqual({ + object: 'agent_instance_session', + id: 'agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY', + agentInstanceId: 'agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY', + status: 'revoked', + expiresAt: '2099-01-01T00:00:00.000Z', + revokedAt: '2023-07-18T02:08:00.000Z', + createdAt: '2023-07-18T02:07:19.911Z', + updatedAt: '2023-07-18T02:07:19.911Z', + }); + }); + }); }); diff --git a/src/agents/agents.ts b/src/agents/agents.ts index 97d6eb165..8af4ede32 100644 --- a/src/agents/agents.ts +++ b/src/agents/agents.ts @@ -1,7 +1,25 @@ import { getJose } from '../utils/jose'; +import { AutoPaginatable } from '../common/utils/pagination'; +import { fetchAndDeserialize } from '../common/utils/fetch-and-deserialize'; import { WorkOS } from '../workos'; import { + AgentBlueprint, AgentCredentialValidation, + AgentInstance, + AgentInstanceSession, + AgentToken, + CreateAgentBlueprintOptions, + ListAgentBlueprintsOptions, + ListAgentInstanceSessionsOptions, + ListAgentInstancesOptions, + MintAgentTokenOptions, + SerializedAgentBlueprint, + SerializedAgentInstance, + SerializedAgentInstanceSession, + SerializedAgentToken, + SerializedListAgentInstanceSessionsOptions, + SerializedListAgentInstancesOptions, + UpdateAgentBlueprintOptions, AgentRegistration, ClaimAttemptResponse, LinkClaimAttemptToExternalUserOptions, @@ -14,6 +32,15 @@ import { } from './interfaces'; import { deserializeAgentAccessTokenClaims, + deserializeAgentBlueprint, + deserializeAgentInstance, + deserializeAgentInstanceSession, + deserializeAgentToken, + serializeCreateAgentBlueprintOptions, + serializeListAgentInstanceSessionsOptions, + serializeListAgentInstancesOptions, + serializeMintAgentTokenOptions, + serializeUpdateAgentBlueprintOptions, deserializeAgentCredentialValidation, deserializeAgentRegistration, deserializeClaimAttemptResponse, @@ -46,6 +73,302 @@ export class Agents { constructor(private readonly workos: WorkOS) {} + /** + * Create an agent blueprint + * + * Creates an agent blueprint: the template describing what an agent may do + * (its permission ceiling), who may invoke it, and the lifetimes of its + * sessions. + * + * @param options - Configuration for the new agent blueprint. + * @returns {Promise} + * @throws {BadRequestException} 400 + * @throws {ConflictException} 409 - Name already in use. + * @throws {UnprocessableEntityException} 422 - Permission, role, or organization not found. + */ + async createBlueprint( + options: CreateAgentBlueprintOptions, + ): Promise { + const { data } = await this.workos.post( + '/agents/blueprints', + serializeCreateAgentBlueprintOptions(options), + ); + + return deserializeAgentBlueprint(data); + } + + /** + * List agent blueprints + * + * Lists the agent blueprints in the current environment. + * + * @param options - Pagination options. + * @returns {Promise>} + */ + async listBlueprints( + options?: ListAgentBlueprintsOptions, + ): Promise> { + return new AutoPaginatable( + await fetchAndDeserialize( + this.workos, + '/agents/blueprints', + deserializeAgentBlueprint, + options, + ), + (params) => + fetchAndDeserialize( + this.workos, + '/agents/blueprints', + deserializeAgentBlueprint, + params, + ), + options, + ); + } + + /** + * Get an agent blueprint + * + * Retrieves an agent blueprint by ID. + * @param agentBlueprintId - Unique identifier of the agent blueprint. + * + * @example + * "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async getBlueprint(agentBlueprintId: string): Promise { + const { data } = await this.workos.get( + `/agents/blueprints/${encodeURIComponent(agentBlueprintId)}`, + ); + + return deserializeAgentBlueprint(data); + } + + /** + * Update an agent blueprint + * + * Updates an agent blueprint. Omitted fields are left unchanged; provided + * lists replace the existing configuration. + * + * @param options - Object containing the agent blueprint ID and the fields to update. + * @returns {Promise} + * @throws {BadRequestException} 400 + * @throws {NotFoundException} 404 + * @throws {ConflictException} 409 - Name already in use. + * @throws {UnprocessableEntityException} 422 - Permission, role, or organization not found. + */ + async updateBlueprint( + options: UpdateAgentBlueprintOptions, + ): Promise { + const { agentBlueprintId, ...payload } = options; + + const { data } = await this.workos.patch( + `/agents/blueprints/${encodeURIComponent(agentBlueprintId)}`, + serializeUpdateAgentBlueprintOptions(payload), + ); + + return deserializeAgentBlueprint(data); + } + + /** + * Delete an agent blueprint + * + * Deletes an agent blueprint by ID. + * @param agentBlueprintId - Unique identifier of the agent blueprint. + * + * @example + * "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async deleteBlueprint(agentBlueprintId: string): Promise { + await this.workos.delete( + `/agents/blueprints/${encodeURIComponent(agentBlueprintId)}`, + ); + } + + /** + * Mint an agent token + * + * Mints tokens for an agent session from a blueprint. Supports + * user-delegated, autonomous, and agent-delegated mints, as well as + * refreshing an existing session with a refresh token. + * + * @param options - Object containing the agent blueprint ID, the mint type, and its credentials. + * @returns {Promise} + * @throws {BadRequestException} 400 + * @throws {NotFoundException} 404 + */ + async mintToken(options: MintAgentTokenOptions): Promise { + const { data } = await this.workos.post( + `/agents/blueprints/${encodeURIComponent(options.agentBlueprintId)}/tokens`, + serializeMintAgentTokenOptions(options), + ); + + return deserializeAgentToken(data); + } + + /** + * List agent instances + * + * Lists the agent instances in the current environment, optionally filtered + * by organization or agent blueprint. + * + * @param options - Pagination and filter options. + * @returns {Promise>} + */ + async listInstances( + options?: ListAgentInstancesOptions, + ): Promise< + AutoPaginatable + > { + return new AutoPaginatable( + await fetchAndDeserialize( + this.workos, + '/agents/instances', + deserializeAgentInstance, + options ? serializeListAgentInstancesOptions(options) : undefined, + ), + (params) => + fetchAndDeserialize( + this.workos, + '/agents/instances', + deserializeAgentInstance, + params, + ), + options ? serializeListAgentInstancesOptions(options) : undefined, + ); + } + + /** + * Get an agent instance + * + * Retrieves an agent instance by ID. + * @param agentInstanceId - Unique identifier of the agent instance. + * + * @example + * "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async getInstance(agentInstanceId: string): Promise { + const { data } = await this.workos.get( + `/agents/instances/${encodeURIComponent(agentInstanceId)}`, + ); + + return deserializeAgentInstance(data); + } + + /** + * Delete an agent instance + * + * Deletes an agent instance by ID. + * @param agentInstanceId - Unique identifier of the agent instance. + * + * @example + * "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async deleteInstance(agentInstanceId: string): Promise { + await this.workos.delete( + `/agents/instances/${encodeURIComponent(agentInstanceId)}`, + ); + } + + /** + * List agent instance sessions + * + * Lists the agent instance sessions in the current environment, optionally + * filtered by agent blueprint or agent instance. + * + * @param options - Pagination and filter options. + * @returns {Promise>} + */ + async listInstanceSessions( + options?: ListAgentInstanceSessionsOptions, + ): Promise< + AutoPaginatable< + AgentInstanceSession, + SerializedListAgentInstanceSessionsOptions + > + > { + return new AutoPaginatable( + await fetchAndDeserialize< + SerializedAgentInstanceSession, + AgentInstanceSession + >( + this.workos, + '/agents/sessions', + deserializeAgentInstanceSession, + options + ? serializeListAgentInstanceSessionsOptions(options) + : undefined, + ), + (params) => + fetchAndDeserialize< + SerializedAgentInstanceSession, + AgentInstanceSession + >( + this.workos, + '/agents/sessions', + deserializeAgentInstanceSession, + params, + ), + options ? serializeListAgentInstanceSessionsOptions(options) : undefined, + ); + } + + /** + * Get an agent instance session + * + * Retrieves an agent instance session by ID. + * @param agentInstanceSessionId - Unique identifier of the agent instance session. + * + * @example + * "agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async getInstanceSession( + agentInstanceSessionId: string, + ): Promise { + const { data } = await this.workos.get( + `/agents/sessions/${encodeURIComponent(agentInstanceSessionId)}`, + ); + + return deserializeAgentInstanceSession(data); + } + + /** + * Revoke an agent instance session + * + * Revokes an agent instance session by ID, invalidating its tokens. + * @param agentInstanceSessionId - Unique identifier of the agent instance session. + * + * @example + * "agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY" + * + * @returns {Promise} + * @throws {NotFoundException} 404 + */ + async revokeInstanceSession( + agentInstanceSessionId: string, + ): Promise { + const { data } = await this.workos.post( + `/agents/sessions/${encodeURIComponent(agentInstanceSessionId)}/revoke`, + {}, + ); + + return deserializeAgentInstanceSession(data); + } + /** * Link a claim attempt to an external user * diff --git a/src/agents/fixtures/get-agent-blueprint.json b/src/agents/fixtures/get-agent-blueprint.json new file mode 100644 index 000000000..a3baf1c09 --- /dev/null +++ b/src/agents/fixtures/get-agent-blueprint.json @@ -0,0 +1,18 @@ +{ + "object": "agent_blueprint", + "id": "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Prospecting Agent", + "description": "Finds and qualifies sales prospects.", + "permissions": ["crm:read", "email:send"], + "invocable_by": { + "role_slugs": ["manager"], + "organization_ids": ["org_01EHWNCE74X7JSDV0X3SZ3KJNY"] + }, + "session_settings": { + "max_age_seconds": 3600, + "access_token_ttl_seconds": 300, + "refresh_token_ttl_seconds": 3600 + }, + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" +} diff --git a/src/agents/fixtures/get-agent-instance-session.json b/src/agents/fixtures/get-agent-instance-session.json new file mode 100644 index 000000000..97856d91f --- /dev/null +++ b/src/agents/fixtures/get-agent-instance-session.json @@ -0,0 +1,10 @@ +{ + "object": "agent_instance_session", + "id": "agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_instance_id": "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "expires_at": "2099-01-01T00:00:00.000Z", + "revoked_at": null, + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" +} diff --git a/src/agents/fixtures/get-agent-instance.json b/src/agents/fixtures/get-agent-instance.json new file mode 100644 index 000000000..9dc2b3dee --- /dev/null +++ b/src/agents/fixtures/get-agent-instance.json @@ -0,0 +1,10 @@ +{ + "object": "agent_instance", + "id": "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_blueprint_id": "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_membership_id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "delegated", + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" +} diff --git a/src/agents/fixtures/list-agent-blueprints.json b/src/agents/fixtures/list-agent-blueprints.json new file mode 100644 index 000000000..86bc7eeff --- /dev/null +++ b/src/agents/fixtures/list-agent-blueprints.json @@ -0,0 +1,27 @@ +{ + "object": "list", + "data": [ + { + "object": "agent_blueprint", + "id": "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Prospecting Agent", + "description": "Finds and qualifies sales prospects.", + "permissions": ["crm:read", "email:send"], + "invocable_by": { + "role_slugs": ["manager"], + "organization_ids": ["org_01EHWNCE74X7JSDV0X3SZ3KJNY"] + }, + "session_settings": { + "max_age_seconds": 3600, + "access_token_ttl_seconds": 300, + "refresh_token_ttl_seconds": 3600 + }, + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/src/agents/fixtures/list-agent-instance-sessions.json b/src/agents/fixtures/list-agent-instance-sessions.json new file mode 100644 index 000000000..ac8c858bb --- /dev/null +++ b/src/agents/fixtures/list-agent-instance-sessions.json @@ -0,0 +1,19 @@ +{ + "object": "list", + "data": [ + { + "object": "agent_instance_session", + "id": "agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_instance_id": "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "expires_at": "2099-01-01T00:00:00.000Z", + "revoked_at": null, + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/src/agents/fixtures/list-agent-instances.json b/src/agents/fixtures/list-agent-instances.json new file mode 100644 index 000000000..3b2887fd2 --- /dev/null +++ b/src/agents/fixtures/list-agent-instances.json @@ -0,0 +1,19 @@ +{ + "object": "list", + "data": [ + { + "object": "agent_instance", + "id": "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_blueprint_id": "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_membership_id": null, + "type": "autonomous", + "created_at": "2023-07-18T02:07:19.911Z", + "updated_at": "2023-07-18T02:07:19.911Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/src/agents/fixtures/mint-agent-token.json b/src/agents/fixtures/mint-agent-token.json new file mode 100644 index 000000000..5843f4c63 --- /dev/null +++ b/src/agents/fixtures/mint-agent-token.json @@ -0,0 +1,10 @@ +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.example.token", + "token_type": "Bearer", + "expires_in": 300, + "refresh_token": "refresh_token_example", + "agent_instance_id": "agent_instance_01EHWNCE74X7JSDV0X3SZ3KJNY", + "new_instance": true, + "agent_instance_session_id": "agent_instance_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "permissions": ["crm:read", "email:send"] +} diff --git a/src/agents/interfaces/agent-blueprint.interface.ts b/src/agents/interfaces/agent-blueprint.interface.ts new file mode 100644 index 000000000..491787137 --- /dev/null +++ b/src/agents/interfaces/agent-blueprint.interface.ts @@ -0,0 +1,160 @@ +import { PaginationOptions } from '../../common/interfaces/pagination-options.interface'; + +/** Who may mint sessions from an agent blueprint. */ +export interface AgentBlueprintInvocableBy { + /** + * Role slugs whose members may mint user-delegated sessions from the + * blueprint. An empty list allows any member. + */ + roleSlugs: string[]; + /** + * Organizations in which sessions may be minted from the blueprint. An empty + * list allows any organization in the environment. + */ + organizationIds: string[]; +} + +export interface SerializedAgentBlueprintInvocableBy { + role_slugs: string[]; + organization_ids: string[]; +} + +/** Token and session lifetimes for sessions minted from an agent blueprint. */ +export interface AgentBlueprintSessionSettings { + /** + * Maximum lifetime of a session in seconds; refreshes never extend a session + * past this. At most 31,536,000 (365 days). + */ + maxAgeSeconds: number; + /** Lifetime of each minted access token in seconds. At most 3,600 (1 hour). */ + accessTokenTtlSeconds: number; + /** Lifetime of each rotated refresh token in seconds. At most 5,184,000 (60 days). */ + refreshTokenTtlSeconds: number; +} + +export interface SerializedAgentBlueprintSessionSettings { + max_age_seconds: number; + access_token_ttl_seconds: number; + refresh_token_ttl_seconds: number; +} + +/** + * An agent blueprint: the template describing what an agent may do (its + * permission ceiling), who may invoke it, and the lifetimes of its sessions. + */ +export interface AgentBlueprint { + object: 'agent_blueprint'; + /** Unique identifier of the agent blueprint. */ + id: string; + /** Human-readable name of the agent blueprint. */ + name: string; + /** Human-readable description of the agent blueprint. */ + description: string | null; + /** + * Permission slugs forming the ceiling on what sessions minted from the + * blueprint may do. + */ + permissions: string[]; + /** Who may mint sessions from the blueprint. */ + invocableBy: AgentBlueprintInvocableBy; + /** Token and session lifetimes for sessions minted from the blueprint. */ + sessionSettings: AgentBlueprintSessionSettings; + /** An ISO 8601 timestamp. */ + createdAt: string; + /** An ISO 8601 timestamp. */ + updatedAt: string; +} + +export interface SerializedAgentBlueprint { + object: 'agent_blueprint'; + id: string; + name: string; + description: string | null; + permissions: string[]; + invocable_by: SerializedAgentBlueprintInvocableBy; + session_settings: SerializedAgentBlueprintSessionSettings; + created_at: string; + updated_at: string; +} + +/** Options for creating an agent blueprint. */ +export interface CreateAgentBlueprintOptions { + /** Human-readable name of the agent blueprint. */ + name: string; + /** Human-readable description of the agent blueprint. */ + description?: string; + /** + * Permission slugs forming the ceiling on what sessions minted from the + * blueprint may do. Each slug must exist in the environment. + */ + permissions?: string[]; + /** Who may mint sessions from the blueprint. */ + invocableBy?: { + roleSlugs?: string[]; + organizationIds?: string[]; + }; + /** Token and session lifetimes for sessions minted from the blueprint. */ + sessionSettings: { + maxAgeSeconds: number; + accessTokenTtlSeconds: number; + refreshTokenTtlSeconds: number; + }; +} + +export interface SerializedCreateAgentBlueprintOptions { + name: string; + description?: string; + permissions?: string[]; + invocable_by?: { + role_slugs?: string[]; + organization_ids?: string[]; + }; + session_settings: SerializedAgentBlueprintSessionSettings; +} + +/** + * Options for updating an agent blueprint. Omitted fields are left unchanged; + * provided lists replace the existing configuration. + */ +export interface UpdateAgentBlueprintOptions { + /** Unique identifier of the agent blueprint. */ + agentBlueprintId: string; + /** Human-readable name of the agent blueprint. */ + name?: string; + /** Human-readable description of the agent blueprint, or `null` to clear it. */ + description?: string | null; + /** + * Permission slugs forming the ceiling on what sessions minted from the + * blueprint may do. Each slug must exist in the environment. + */ + permissions?: string[]; + /** Who may mint sessions from the blueprint. */ + invocableBy?: { + roleSlugs?: string[]; + organizationIds?: string[]; + }; + /** Token and session lifetimes for sessions minted from the blueprint. */ + sessionSettings?: { + maxAgeSeconds?: number; + accessTokenTtlSeconds?: number; + refreshTokenTtlSeconds?: number; + }; +} + +export interface SerializedUpdateAgentBlueprintOptions { + name?: string; + description?: string | null; + permissions?: string[]; + invocable_by?: { + role_slugs?: string[]; + organization_ids?: string[]; + }; + session_settings?: { + max_age_seconds?: number; + access_token_ttl_seconds?: number; + refresh_token_ttl_seconds?: number; + }; +} + +/** Options for listing agent blueprints. */ +export type ListAgentBlueprintsOptions = PaginationOptions; diff --git a/src/agents/interfaces/agent-instance-session.interface.ts b/src/agents/interfaces/agent-instance-session.interface.ts new file mode 100644 index 000000000..50363093f --- /dev/null +++ b/src/agents/interfaces/agent-instance-session.interface.ts @@ -0,0 +1,47 @@ +import { PaginationOptions } from '../../common/interfaces/pagination-options.interface'; + +/** The lifecycle status of an agent instance session. */ +export type AgentInstanceSessionStatus = 'active' | 'revoked' | 'expired'; + +/** A session minted for an agent instance. */ +export interface AgentInstanceSession { + object: 'agent_instance_session'; + /** Unique identifier of the agent instance session. */ + id: string; + /** Unique identifier of the agent instance the session belongs to. */ + agentInstanceId: string; + /** The lifecycle status of the session. */ + status: AgentInstanceSessionStatus; + /** An ISO 8601 timestamp of when the session expires. */ + expiresAt: string; + /** An ISO 8601 timestamp of when the session was revoked, or `null`. */ + revokedAt: string | null; + /** An ISO 8601 timestamp. */ + createdAt: string; + /** An ISO 8601 timestamp. */ + updatedAt: string; +} + +export interface SerializedAgentInstanceSession { + object: 'agent_instance_session'; + id: string; + agent_instance_id: string; + status: AgentInstanceSessionStatus; + expires_at: string; + revoked_at: string | null; + created_at: string; + updated_at: string; +} + +/** Options for listing agent instance sessions. */ +export interface ListAgentInstanceSessionsOptions extends PaginationOptions { + /** Filter sessions to a single agent blueprint. */ + agentBlueprintId?: string; + /** Filter sessions to a single agent instance. */ + agentInstanceId?: string; +} + +export interface SerializedListAgentInstanceSessionsOptions extends PaginationOptions { + agent_blueprint_id?: string; + agent_instance_id?: string; +} diff --git a/src/agents/interfaces/agent-instance.interface.ts b/src/agents/interfaces/agent-instance.interface.ts new file mode 100644 index 000000000..59dbf9ff3 --- /dev/null +++ b/src/agents/interfaces/agent-instance.interface.ts @@ -0,0 +1,50 @@ +import { PaginationOptions } from '../../common/interfaces/pagination-options.interface'; + +/** How an agent instance was minted. */ +export type AgentInstanceType = 'delegated' | 'autonomous'; + +/** A concrete agent minted from an agent blueprint. */ +export interface AgentInstance { + object: 'agent_instance'; + /** Unique identifier of the agent instance. */ + id: string; + /** Unique identifier of the agent blueprint the instance was minted from. */ + agentBlueprintId: string; + /** Unique identifier of the Organization the instance belongs to. */ + organizationId: string; + /** + * Unique identifier of the Organization Membership the instance acts on + * behalf of, or `null` for autonomous instances. + */ + organizationMembershipId: string | null; + /** How the instance was minted. */ + type: AgentInstanceType; + /** An ISO 8601 timestamp. */ + createdAt: string; + /** An ISO 8601 timestamp. */ + updatedAt: string; +} + +export interface SerializedAgentInstance { + object: 'agent_instance'; + id: string; + agent_blueprint_id: string; + organization_id: string; + organization_membership_id: string | null; + type: AgentInstanceType; + created_at: string; + updated_at: string; +} + +/** Options for listing agent instances. */ +export interface ListAgentInstancesOptions extends PaginationOptions { + /** Filter instances to a single Organization. */ + organizationId?: string; + /** Filter instances to a single agent blueprint. */ + agentBlueprintId?: string; +} + +export interface SerializedListAgentInstancesOptions extends PaginationOptions { + organization_id?: string; + agent_blueprint_id?: string; +} diff --git a/src/agents/interfaces/agent-token.interface.ts b/src/agents/interfaces/agent-token.interface.ts new file mode 100644 index 000000000..8d9600b9c --- /dev/null +++ b/src/agents/interfaces/agent-token.interface.ts @@ -0,0 +1,94 @@ +/** Tokens minted for an agent session. */ +export interface AgentToken { + /** The access token for the agent session. */ + accessToken: string; + /** The token type, always `Bearer`. */ + tokenType: 'Bearer'; + /** Number of seconds until the access token expires. */ + expiresIn: number; + /** The refresh token for the agent session. */ + refreshToken: string; + /** Unique identifier of the agent instance the token belongs to. */ + agentInstanceId: string; + /** Whether a new agent instance was created by this mint. */ + newInstance: boolean; + /** Unique identifier of the agent instance session the token belongs to. */ + agentInstanceSessionId: string; + /** The permission slugs granted to the session. */ + permissions: string[]; +} + +export interface SerializedAgentToken { + access_token: string; + token_type: 'Bearer'; + expires_in: number; + refresh_token: string; + agent_instance_id: string; + new_instance: boolean; + agent_instance_session_id: string; + permissions: string[]; +} + +interface MintAgentTokenBaseOptions { + /** Unique identifier of the agent blueprint to mint from. */ + agentBlueprintId: string; + /** A free-form description of what the session is intended to do. */ + intent?: string; +} + +/** Options for minting a user-delegated agent token. */ +export interface MintUserDelegatedAgentTokenOptions extends MintAgentTokenBaseOptions { + type: 'user_delegated'; + /** The access token of the user delegating to the agent. */ + userAccessToken: string; +} + +/** Options for minting an autonomous agent token. */ +export interface MintAutonomousAgentTokenOptions extends MintAgentTokenBaseOptions { + type: 'autonomous'; + /** The organization in which to mint the session. */ + organizationId: string; +} + +/** Options for minting an agent-delegated agent token. */ +export interface MintAgentDelegatedAgentTokenOptions extends MintAgentTokenBaseOptions { + type: 'agent_delegated'; + /** The access token of the agent delegating to the new agent. */ + agentAccessToken: string; +} + +/** Options for refreshing an agent token. */ +export interface RefreshAgentTokenOptions extends MintAgentTokenBaseOptions { + type: 'refresh'; + /** The refresh token from a previous mint. */ + refreshToken: string; +} + +/** Options for minting an agent token from a blueprint. */ +export type MintAgentTokenOptions = + | MintUserDelegatedAgentTokenOptions + | MintAutonomousAgentTokenOptions + | MintAgentDelegatedAgentTokenOptions + | RefreshAgentTokenOptions; + +export type SerializedMintAgentTokenOptions = + | { + type: 'user_delegated'; + user_access_token: string; + intent?: string; + } + | { + type: 'autonomous'; + organization_id: string; + intent?: string; + } + | { + type: 'agent_delegated'; + agent_access_token: string; + intent?: string; + } + | { + type: 'refresh'; + refresh_token: string; + intent?: string; + }; diff --git a/src/agents/interfaces/index.ts b/src/agents/interfaces/index.ts index eaa6bf490..934d39095 100644 --- a/src/agents/interfaces/index.ts +++ b/src/agents/interfaces/index.ts @@ -1,3 +1,7 @@ +export * from './agent-blueprint.interface'; +export * from './agent-instance-session.interface'; +export * from './agent-instance.interface'; export * from './agent-registration.interface'; +export * from './agent-token.interface'; export * from './claim-attempt.interface'; export * from './validate-agent-credential.interface'; diff --git a/src/agents/serializers/agent-blueprint.serializer.ts b/src/agents/serializers/agent-blueprint.serializer.ts new file mode 100644 index 000000000..c4d67080a --- /dev/null +++ b/src/agents/serializers/agent-blueprint.serializer.ts @@ -0,0 +1,101 @@ +import { + AgentBlueprint, + CreateAgentBlueprintOptions, + SerializedAgentBlueprint, + SerializedCreateAgentBlueprintOptions, + SerializedUpdateAgentBlueprintOptions, + UpdateAgentBlueprintOptions, +} from '../interfaces/agent-blueprint.interface'; + +export function deserializeAgentBlueprint( + blueprint: SerializedAgentBlueprint, +): AgentBlueprint { + return { + object: blueprint.object, + id: blueprint.id, + name: blueprint.name, + description: blueprint.description, + permissions: blueprint.permissions, + invocableBy: { + roleSlugs: blueprint.invocable_by.role_slugs, + organizationIds: blueprint.invocable_by.organization_ids, + }, + sessionSettings: { + maxAgeSeconds: blueprint.session_settings.max_age_seconds, + accessTokenTtlSeconds: + blueprint.session_settings.access_token_ttl_seconds, + refreshTokenTtlSeconds: + blueprint.session_settings.refresh_token_ttl_seconds, + }, + createdAt: blueprint.created_at, + updatedAt: blueprint.updated_at, + }; +} + +export function serializeCreateAgentBlueprintOptions( + options: CreateAgentBlueprintOptions, +): SerializedCreateAgentBlueprintOptions { + return { + name: options.name, + ...(options.description !== undefined && { + description: options.description, + }), + ...(options.permissions !== undefined && { + permissions: options.permissions, + }), + ...(options.invocableBy !== undefined && { + invocable_by: { + ...(options.invocableBy.roleSlugs !== undefined && { + role_slugs: options.invocableBy.roleSlugs, + }), + ...(options.invocableBy.organizationIds !== undefined && { + organization_ids: options.invocableBy.organizationIds, + }), + }, + }), + session_settings: { + max_age_seconds: options.sessionSettings.maxAgeSeconds, + access_token_ttl_seconds: options.sessionSettings.accessTokenTtlSeconds, + refresh_token_ttl_seconds: options.sessionSettings.refreshTokenTtlSeconds, + }, + }; +} + +export function serializeUpdateAgentBlueprintOptions( + options: Omit, +): SerializedUpdateAgentBlueprintOptions { + return { + ...(options.name !== undefined && { name: options.name }), + ...(options.description !== undefined && { + description: options.description, + }), + ...(options.permissions !== undefined && { + permissions: options.permissions, + }), + ...(options.invocableBy !== undefined && { + invocable_by: { + ...(options.invocableBy.roleSlugs !== undefined && { + role_slugs: options.invocableBy.roleSlugs, + }), + ...(options.invocableBy.organizationIds !== undefined && { + organization_ids: options.invocableBy.organizationIds, + }), + }, + }), + ...(options.sessionSettings !== undefined && { + session_settings: { + ...(options.sessionSettings.maxAgeSeconds !== undefined && { + max_age_seconds: options.sessionSettings.maxAgeSeconds, + }), + ...(options.sessionSettings.accessTokenTtlSeconds !== undefined && { + access_token_ttl_seconds: + options.sessionSettings.accessTokenTtlSeconds, + }), + ...(options.sessionSettings.refreshTokenTtlSeconds !== undefined && { + refresh_token_ttl_seconds: + options.sessionSettings.refreshTokenTtlSeconds, + }), + }, + }), + }; +} diff --git a/src/agents/serializers/agent-instance-session.serializer.ts b/src/agents/serializers/agent-instance-session.serializer.ts new file mode 100644 index 000000000..389abcc53 --- /dev/null +++ b/src/agents/serializers/agent-instance-session.serializer.ts @@ -0,0 +1,34 @@ +import { + AgentInstanceSession, + ListAgentInstanceSessionsOptions, + SerializedAgentInstanceSession, + SerializedListAgentInstanceSessionsOptions, +} from '../interfaces/agent-instance-session.interface'; + +export function deserializeAgentInstanceSession( + session: SerializedAgentInstanceSession, +): AgentInstanceSession { + return { + object: session.object, + id: session.id, + agentInstanceId: session.agent_instance_id, + status: session.status, + expiresAt: session.expires_at, + revokedAt: session.revoked_at, + createdAt: session.created_at, + updatedAt: session.updated_at, + }; +} + +export function serializeListAgentInstanceSessionsOptions( + options: ListAgentInstanceSessionsOptions, +): SerializedListAgentInstanceSessionsOptions { + return { + agent_blueprint_id: options.agentBlueprintId, + agent_instance_id: options.agentInstanceId, + limit: options.limit, + before: options.before, + after: options.after, + order: options.order, + }; +} diff --git a/src/agents/serializers/agent-instance.serializer.ts b/src/agents/serializers/agent-instance.serializer.ts new file mode 100644 index 000000000..b4a2be8f1 --- /dev/null +++ b/src/agents/serializers/agent-instance.serializer.ts @@ -0,0 +1,34 @@ +import { + AgentInstance, + ListAgentInstancesOptions, + SerializedAgentInstance, + SerializedListAgentInstancesOptions, +} from '../interfaces/agent-instance.interface'; + +export function deserializeAgentInstance( + instance: SerializedAgentInstance, +): AgentInstance { + return { + object: instance.object, + id: instance.id, + agentBlueprintId: instance.agent_blueprint_id, + organizationId: instance.organization_id, + organizationMembershipId: instance.organization_membership_id, + type: instance.type, + createdAt: instance.created_at, + updatedAt: instance.updated_at, + }; +} + +export function serializeListAgentInstancesOptions( + options: ListAgentInstancesOptions, +): SerializedListAgentInstancesOptions { + return { + organization_id: options.organizationId, + agent_blueprint_id: options.agentBlueprintId, + limit: options.limit, + before: options.before, + after: options.after, + order: options.order, + }; +} diff --git a/src/agents/serializers/agent-token.serializer.ts b/src/agents/serializers/agent-token.serializer.ts new file mode 100644 index 000000000..0c82ae8d3 --- /dev/null +++ b/src/agents/serializers/agent-token.serializer.ts @@ -0,0 +1,52 @@ +import { + AgentToken, + MintAgentTokenOptions, + SerializedAgentToken, + SerializedMintAgentTokenOptions, +} from '../interfaces/agent-token.interface'; + +export function deserializeAgentToken(token: SerializedAgentToken): AgentToken { + return { + accessToken: token.access_token, + tokenType: token.token_type, + expiresIn: token.expires_in, + refreshToken: token.refresh_token, + agentInstanceId: token.agent_instance_id, + newInstance: token.new_instance, + agentInstanceSessionId: token.agent_instance_session_id, + permissions: token.permissions, + }; +} + +export function serializeMintAgentTokenOptions( + options: MintAgentTokenOptions, +): SerializedMintAgentTokenOptions { + const intent = options.intent !== undefined ? { intent: options.intent } : {}; + + switch (options.type) { + case 'user_delegated': + return { + type: 'user_delegated', + user_access_token: options.userAccessToken, + ...intent, + }; + case 'autonomous': + return { + type: 'autonomous', + organization_id: options.organizationId, + ...intent, + }; + case 'agent_delegated': + return { + type: 'agent_delegated', + agent_access_token: options.agentAccessToken, + ...intent, + }; + case 'refresh': + return { + type: 'refresh', + refresh_token: options.refreshToken, + ...intent, + }; + } +} diff --git a/src/agents/serializers/index.ts b/src/agents/serializers/index.ts index ccc8d7b73..e65186141 100644 --- a/src/agents/serializers/index.ts +++ b/src/agents/serializers/index.ts @@ -1,3 +1,7 @@ +export * from './agent-blueprint.serializer'; +export * from './agent-instance-session.serializer'; +export * from './agent-instance.serializer'; export * from './agent-registration.serializer'; +export * from './agent-token.serializer'; export * from './claim-attempt.serializer'; export * from './validate-agent-credential.serializer';