UNPKG

@sap-ai-sdk/orchestration

Version:

SAP Cloud SDK for AI is the official Software Development Kit (SDK) for **SAP AI Core**, **SAP Generative AI Hub**, and **Orchestration Service**.

152 lines 6.23 kB
import { executeRequest } from '@sap-ai-sdk/core'; import { createLogger } from '@sap-cloud-sdk/util'; import yaml from 'yaml'; import { registryControllerPromptControllerCreateUpdatePromptTemplateBody } from '@sap-ai-sdk/prompt-registry/internal.js'; import { getOrchestrationDeploymentId } from './deployment-resolver.js'; import { OrchestrationStream } from './orchestration-stream.js'; import { OrchestrationStreamResponse } from './orchestration-stream-response.js'; import { OrchestrationResponse } from './orchestration-response.js'; import { constructCompletionPostRequest, constructCompletionPostRequestFromJsonModuleConfig } from './util/index.js'; const logger = createLogger({ package: 'orchestration', messageContext: 'orchestration-client' }); /** * Get the orchestration client. */ export class OrchestrationClient { config; deploymentConfig; destination; /** * Creates an instance of the orchestration client. * @param config - Orchestration module configuration. This can either be an `OrchestrationModuleConfig` object or a JSON string obtained from AI Launchpad. * @param deploymentConfig - Deployment configuration. * @param destination - The destination to use for the request. */ constructor(config, deploymentConfig, destination) { this.config = config; this.deploymentConfig = deploymentConfig; this.destination = destination; if (typeof config === 'string') { this.validateJsonConfig(config); } else { this.config = typeof config.promptTemplating.prompt === 'string' ? this.parseAndMergeTemplating(config) // parse and assign if templating is a string : config; } } async chatCompletion(request, requestConfig) { const response = await this.executeRequest({ request, requestConfig, stream: false }); return new OrchestrationResponse(response); } async stream(request, signal, options, requestConfig) { const controller = new AbortController(); if (signal) { signal.addEventListener('abort', () => { controller.abort(); }); } try { if (typeof this.config === 'string' && options) { logger.warn('Stream options are not supported when using a JSON module config.'); } return await this.createStreamResponse({ request, requestConfig, stream: true, streamOptions: options }, controller); } catch (error) { controller.abort(); throw error; } } async executeRequest(options) { const { request, requestConfig, stream, streamOptions } = options; const body = typeof this.config === 'string' ? constructCompletionPostRequestFromJsonModuleConfig(JSON.parse(this.config), request, stream) : constructCompletionPostRequest(this.config, request, stream, streamOptions); const deploymentId = await getOrchestrationDeploymentId(this.deploymentConfig ?? {}, this.destination); if (!deploymentId) { throw new Error('Failed to resolve deployment ID'); } return executeRequest({ url: `/inference/deployments/${deploymentId}/v2/completion`, ...(this.deploymentConfig ?? {}) }, body, requestConfig, this.destination); } async createStreamResponse(options, controller) { const response = new OrchestrationStreamResponse(); const streamResponse = await this.executeRequest({ ...options, requestConfig: { ...options.requestConfig, responseType: 'stream', signal: controller.signal } }); const stream = OrchestrationStream._create(streamResponse, controller); response.stream = stream ._pipe(OrchestrationStream._processChunk) ._pipe(OrchestrationStream._processOrchestrationStreamChunkResponse, response) ._pipe(OrchestrationStream._processStreamEnd, response); return response; } /** * Validate if a string is valid JSON. * @param config - The JSON string to validate. */ validateJsonConfig(config) { try { JSON.parse(config); } catch (error) { throw new Error(`Could not parse JSON: ${error}`); } } /** * Parse and merge templating into the config object. * @param config - The orchestration module configuration with templating either as object or string. * @returns The updated and merged orchestration module configuration. * @throws Error if the YAML parsing fails or if the parsed object does not conform to the expected schema. */ parseAndMergeTemplating(config) { let parsedObject; if (typeof config.promptTemplating.prompt === 'string' && !config.promptTemplating.prompt.trim()) { throw new Error('Templating YAML string must be non-empty.'); } try { parsedObject = yaml.parse(config.promptTemplating.prompt); } catch (error) { throw new Error(`Error parsing YAML: ${error}`); } const result = registryControllerPromptControllerCreateUpdatePromptTemplateBody.safeParse(parsedObject); if (!result.success) { throw new Error(`Prompt Template YAML does not conform to the defined type. Validation errors: ${result.error}`); } const { template, defaults, response_format, tools } = result.data.spec; return { ...config, promptTemplating: { ...config.promptTemplating, prompt: { template: template, ...(defaults && { defaults }), ...(response_format && { response_format }), ...(tools && { tools }) } } }; } } //# sourceMappingURL=orchestration-client.js.map