|
| 1 | +import { Gradient } from '../../client'; |
| 2 | +import { RequestOptions } from '../../internal/request-options'; |
| 3 | +import { GradientError } from '../../core/error'; |
| 4 | +import { sleep } from '../../internal/utils'; |
| 5 | +import { AgentReadinessResponse, APIAgent } from './agents'; |
| 6 | + |
| 7 | +type AgentStatus = NonNullable<APIAgent.Deployment['status']>; |
| 8 | + |
| 9 | +export interface WaitForAgentOptions extends RequestOptions { |
| 10 | + /** Check interval in ms (default: 3000) */ |
| 11 | + interval?: number; |
| 12 | +} |
| 13 | + |
| 14 | +export class AgentTimeoutError extends GradientError { |
| 15 | + constructor( |
| 16 | + public agentId: string, |
| 17 | + public timeoutMs: number, |
| 18 | + ) { |
| 19 | + super(`Agent ${agentId} did not become ready within ${timeoutMs}ms`); |
| 20 | + this.name = 'AgentTimeoutError'; |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +export class AgentDeploymentError extends GradientError { |
| 25 | + constructor( |
| 26 | + public agentId: string, |
| 27 | + public status: AgentStatus, |
| 28 | + ) { |
| 29 | + super(`Agent ${agentId} deployment failed with status: ${status}`); |
| 30 | + this.name = 'AgentDeploymentError'; |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +/** |
| 35 | + * Polls an agent until it reaches STATUS_RUNNING. |
| 36 | + * |
| 37 | + * @example |
| 38 | + * ```typescript |
| 39 | + * const agent = await waitForAgentReady(client, 'agent-123', { |
| 40 | + * timeout: 60000, // 1 minute |
| 41 | + * }); |
| 42 | + * ``` |
| 43 | + * |
| 44 | + * @param client - Gradient API client instance |
| 45 | + * @param uuid - UUID of the agent to monitor |
| 46 | + * @param options - Polling configuration |
| 47 | + * @returns The agent object once STATUS_RUNNING is reached |
| 48 | + * @throws {AgentTimeoutError} When polling exceeds timeout duration |
| 49 | + * @throws {AgentDeploymentError} When agent enters a failure state |
| 50 | + */ |
| 51 | +export async function waitForAgentReady( |
| 52 | + client: Gradient, |
| 53 | + uuid: string, |
| 54 | + options: WaitForAgentOptions = {}, |
| 55 | +): Promise<AgentReadinessResponse> { |
| 56 | + const { interval = 3000, timeout = 180000, signal } = options; |
| 57 | + const start = Date.now(); |
| 58 | + |
| 59 | + while (true) { |
| 60 | + signal?.throwIfAborted(); |
| 61 | + |
| 62 | + const elapsed = Date.now() - start; |
| 63 | + |
| 64 | + // ⏰ Check timeout BEFORE making the API call |
| 65 | + if (elapsed > timeout) { |
| 66 | + throw new AgentTimeoutError(uuid, timeout); |
| 67 | + } |
| 68 | + |
| 69 | + const agent = await client.agents.retrieve(uuid, options); |
| 70 | + const status = (agent.agent?.deployment?.status as AgentStatus) || 'STATUS_UNKNOWN'; |
| 71 | + |
| 72 | + if (status === 'STATUS_RUNNING') { |
| 73 | + return agent; |
| 74 | + } |
| 75 | + |
| 76 | + if (status === 'STATUS_FAILED' || status === 'STATUS_UNDEPLOYMENT_FAILED') { |
| 77 | + throw new AgentDeploymentError(uuid, status); |
| 78 | + } |
| 79 | + |
| 80 | + await sleep(interval); |
| 81 | + } |
| 82 | +} |
0 commit comments