From 184eb3c512a8772ddcf425c5a23d448340d1c75a Mon Sep 17 00:00:00 2001 From: Matthias Kuhr Date: Tue, 11 Feb 2025 10:54:15 +0100 Subject: [PATCH 01/19] Add Response Format Sample Code --- sample-code/src/index.ts | 2 + sample-code/src/orchestration.ts | 58 +++++++++++++++++++++++ sample-code/src/server.ts | 10 +++- tests/e2e-tests/src/orchestration.test.ts | 9 +++- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/sample-code/src/index.ts b/sample-code/src/index.ts index 3ed57633..247bb246 100644 --- a/sample-code/src/index.ts +++ b/sample-code/src/index.ts @@ -18,6 +18,8 @@ export { orchestrationGroundingVector, orchestrationGroundingHelpSapCom, orchestrationChatCompletionImage, + orchestrationResponseFormat, + TranslationResponseType, chatCompletionStreamWithJsonModuleConfig, chatCompletionStream } from './orchestration.js'; diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index ba9511a8..efae79e2 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -482,3 +482,61 @@ export async function orchestrationChatCompletionImage(): Promise { + const orchestrationClient = new OrchestrationClient({ + llm, + templating: { + template: [ + { + role: 'system', + content: + 'You are a helpful AI that translates simple sentences into different languages. The user will provide the sentence. You then choose a language at random and provide the translation.' + }, + { + role: 'user', + content: '{{?input}}' + } + ], + response_format: { + type: 'json_schema', + json_schema: { + name: 'translation_response', + strict: true, + // todo: use ZOD instead, return + schema: { + type: 'object', + properties: { + language: { + type: 'string' + }, + translation: { + type: 'string' + } + }, + required: [ + 'language', + 'translation' + ], + additionalProperties: false + } + } + } + } + }); + + const resonse = await orchestrationClient.chatCompletion({ + inputParams: { + input: 'Hello World! Why is this phrase so famous?' + } + }); + return JSON.parse(resonse.getContent()!) as TranslationResponseType; +} diff --git a/sample-code/src/server.ts b/sample-code/src/server.ts index d9fe94ca..b9676222 100644 --- a/sample-code/src/server.ts +++ b/sample-code/src/server.ts @@ -20,7 +20,8 @@ import { chatCompletionStreamWithJsonModuleConfig as orchestrationChatCompletionStreamWithJsonModuleConfig, orchestrationGroundingHelpSapCom, orchestrationMaskGroundingInput, - orchestrationPromptRegistry + orchestrationPromptRegistry, + orchestrationResponseFormat } from './orchestration.js'; import { getDeployments, @@ -260,7 +261,8 @@ app.get('/orchestration/:sampleCase', async (req, res) => { outputFiltering: orchestrationOutputFiltering, requestConfig: orchestrationRequestConfig, fromJson: orchestrationFromJson, - image: orchestrationChatCompletionImage + image: orchestrationChatCompletionImage, + responseFormat: orchestrationResponseFormat }[sampleCase] || orchestrationChatCompletion; try { @@ -271,6 +273,10 @@ app.get('/orchestration/:sampleCase', async (req, res) => { res.send( `Output filter applied successfully with threshold results: ${JSON.stringify(result.data.module_results.output_filtering!.data!)}` ); + } else if (sampleCase === 'responseFormat') { + res.send( + `Response format applied successfully with response: ${result}` + ); } else { res.send(result.getContent()); } diff --git a/tests/e2e-tests/src/orchestration.test.ts b/tests/e2e-tests/src/orchestration.test.ts index 412590a5..0440e462 100644 --- a/tests/e2e-tests/src/orchestration.test.ts +++ b/tests/e2e-tests/src/orchestration.test.ts @@ -9,7 +9,8 @@ import { orchestrationMaskGroundingInput, orchestrationChatCompletionImage, chatCompletionStreamWithJsonModuleConfig, - chatCompletionStream + chatCompletionStream, + orchestrationResponseFormat } from '@sap-ai-sdk/sample-code'; import { loadEnv } from './utils/load-env.js'; import type { OrchestrationResponse } from '@sap-ai-sdk/orchestration'; @@ -84,6 +85,12 @@ describe('orchestration', () => { expect(response.getContent()?.includes('logo')).toBe(true); }); + it('should complete a chat with a required response format', async () => { + const result = await orchestrationResponseFormat(); + expect(result.language).toBeDefined(); + expect(result.translation).toBeDefined(); + }); + it('should return stream of orchestration responses', async () => { const response = await chatCompletionStream(new AbortController()); From 91d91820bd1eeb0bf427dd79dc9c9b4a5eebd929 Mon Sep 17 00:00:00 2001 From: Matthias Kuhr Date: Wed, 12 Feb 2025 14:50:27 +0100 Subject: [PATCH 02/19] Fix linter --- sample-code/src/orchestration.ts | 14 ++++++++++---- sample-code/src/server.ts | 4 +--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index efae79e2..caaae98a 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -483,8 +483,17 @@ export async function orchestrationChatCompletionImage(): Promise { `Output filter applied successfully with threshold results: ${JSON.stringify(result.data.module_results.output_filtering!.data!)}` ); } else if (sampleCase === 'responseFormat') { - res.send( - `Response format applied successfully with response: ${result}` - ); + res.send(`Response format applied successfully with response: ${result}`); } else { res.send(result.getContent()); } From c9df95643492974e2883a600f64033a1ef18c1b2 Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Thu, 13 Feb 2025 11:38:08 +0100 Subject: [PATCH 03/19] add zod code+dep --- pnpm-lock.yaml | 97 ++++++++++---------------------- sample-code/package.json | 4 +- sample-code/src/orchestration.ts | 21 +++---- 3 files changed, 41 insertions(+), 81 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba1efc6e..b755c505 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,7 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -pnpmfileChecksum: sha256-7lht5Q+T9K1tkr5FYaoHEDBAtJqjkSrAs2jGbKMfTIY= +pnpmfileChecksum: fb3vh7gyjzvxzzal7fbygn3ogm importers: @@ -147,7 +147,7 @@ importers: dependencies: '@langchain/core': specifier: 0.3.39 - version: 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) + version: 0.3.39(openai@4.83.0(zod@3.24.1)) '@sap-ai-sdk/ai-api': specifier: workspace:^ version: link:../ai-api @@ -215,10 +215,10 @@ importers: dependencies: '@langchain/core': specifier: 0.3.39 - version: 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) + version: 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) '@langchain/textsplitters': specifier: 0.1.0 - version: 0.1.0(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1))) + version: 0.1.0(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2))) '@sap-ai-sdk/ai-api': specifier: workspace:^ version: link:../packages/ai-api @@ -245,7 +245,13 @@ importers: version: 4.21.2 langchain: specifier: 0.3.15 - version: 0.3.15(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))(axios@1.7.9)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.83.0(ws@8.18.0)(zod@3.24.1))(ws@8.18.0) + version: 0.3.15(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))(axios@1.7.9)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(ws@8.18.0) + zod: + specifier: ^3.24.2 + version: 3.24.2 + zod-to-json-schema: + specifier: ^3.24.0 + version: 3.24.1(zod@3.24.2) tests/e2e-tests: dependencies: @@ -5951,14 +5957,14 @@ snapshots: transitivePeerDependencies: - openai - '@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1))': + '@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2))': dependencies: '@cfworker/json-schema': 4.1.1 ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.18 - langsmith: 0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) + langsmith: 0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -5968,14 +5974,14 @@ snapshots: transitivePeerDependencies: - openai - '@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2))': + '@langchain/core@0.3.39(openai@4.83.0(zod@3.24.1))': dependencies: '@cfworker/json-schema': 4.1.1 ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.18 - langsmith: 0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) + langsmith: 0.3.7(openai@4.83.0(zod@3.24.1)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -5985,17 +5991,6 @@ snapshots: transitivePeerDependencies: - openai - '@langchain/openai@0.4.3(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))(ws@8.18.0)': - dependencies: - '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) - js-tiktoken: 1.0.18 - openai: 4.83.0(ws@8.18.0)(zod@3.24.2) - zod: 3.24.2 - zod-to-json-schema: 3.24.1(zod@3.24.2) - transitivePeerDependencies: - - encoding - - ws - '@langchain/openai@0.4.3(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))(ws@8.18.0)': dependencies: '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -6007,11 +6002,6 @@ snapshots: - encoding - ws - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))': - dependencies: - '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) - js-tiktoken: 1.0.14 - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))': dependencies: '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -6172,7 +6162,7 @@ snapshots: '@typescript-eslint/parser': 8.22.0(eslint@9.20.1)(typescript@5.7.3) eslint: 9.20.1 eslint-config-prettier: 10.0.1(eslint@9.20.1) - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.1) eslint-plugin-jsdoc: 50.6.3(eslint@9.20.1) eslint-plugin-prettier: 5.2.3(@types/eslint@8.56.10)(eslint-config-prettier@10.0.1(eslint@9.20.1))(eslint@9.20.1)(prettier@3.5.0) @@ -7635,7 +7625,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) @@ -7651,14 +7641,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1))(eslint@9.20.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.22.0(eslint@9.20.1)(typescript@5.7.3) eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1) transitivePeerDependencies: - supports-color @@ -7673,7 +7663,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1))(eslint@9.20.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -9072,30 +9062,6 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.15(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))(axios@1.7.9)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.83.0(ws@8.18.0)(zod@3.24.1))(ws@8.18.0): - dependencies: - '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) - '@langchain/openai': 0.4.3(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))(ws@8.18.0) - '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.1))) - js-tiktoken: 1.0.18 - js-yaml: 4.1.0 - jsonpointer: 5.0.1 - langsmith: 0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) - openapi-types: 12.1.3 - p-retry: 4.6.2 - uuid: 10.0.0 - yaml: 2.7.0 - zod: 3.24.1 - zod-to-json-schema: 3.24.1(zod@3.24.1) - optionalDependencies: - axios: 1.7.9 - cheerio: 1.0.0 - handlebars: 4.7.8 - transitivePeerDependencies: - - encoding - - openai - - ws - langchain@0.3.15(@langchain/core@0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))(axios@1.7.9)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(ws@8.18.0): dependencies: '@langchain/core': 0.3.39(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -9109,8 +9075,8 @@ snapshots: p-retry: 4.6.2 uuid: 10.0.0 yaml: 2.7.0 - zod: 3.24.1 - zod-to-json-schema: 3.24.1(zod@3.24.1) + zod: 3.24.2 + zod-to-json-schema: 3.24.1(zod@3.24.2) optionalDependencies: axios: 1.7.9 cheerio: 1.0.0 @@ -9120,7 +9086,7 @@ snapshots: - openai - ws - langsmith@0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.1)): + langsmith@0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.2)): dependencies: '@types/uuid': 10.0.0 chalk: 4.1.2 @@ -9130,9 +9096,9 @@ snapshots: semver: 7.7.1 uuid: 10.0.0 optionalDependencies: - openai: 4.83.0(ws@8.18.0)(zod@3.24.1) + openai: 4.83.0(ws@8.18.0)(zod@3.24.2) - langsmith@0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.2)): + langsmith@0.3.7(openai@4.83.0(zod@3.24.1)): dependencies: '@types/uuid': 10.0.0 chalk: 4.1.2 @@ -9142,7 +9108,7 @@ snapshots: semver: 7.7.1 uuid: 10.0.0 optionalDependencies: - openai: 4.83.0(ws@8.18.0)(zod@3.24.2) + openai: 4.83.0(zod@3.24.1) leven@3.1.0: {} @@ -9491,7 +9457,7 @@ snapshots: dependencies: mimic-fn: 2.1.0 - openai@4.83.0(ws@8.18.0)(zod@3.24.1): + openai@4.83.0(ws@8.18.0)(zod@3.24.2): dependencies: '@types/node': 18.19.75 '@types/node-fetch': 2.6.12 @@ -9502,12 +9468,11 @@ snapshots: node-fetch: 2.7.0 optionalDependencies: ws: 8.18.0 - zod: 3.24.1 + zod: 3.24.2 transitivePeerDependencies: - encoding - optional: true - openai@4.83.0(ws@8.18.0)(zod@3.24.2): + openai@4.83.0(zod@3.24.1): dependencies: '@types/node': 18.19.75 '@types/node-fetch': 2.6.12 @@ -9517,10 +9482,10 @@ snapshots: formdata-node: 4.4.1 node-fetch: 2.7.0 optionalDependencies: - ws: 8.18.0 - zod: 3.24.2 + zod: 3.24.1 transitivePeerDependencies: - encoding + optional: true openapi-types@12.1.3: {} diff --git a/sample-code/package.json b/sample-code/package.json index 993708c3..012609e9 100644 --- a/sample-code/package.json +++ b/sample-code/package.json @@ -33,6 +33,8 @@ "@langchain/textsplitters": "0.1.0", "@sap-cloud-sdk/util": "^3.26.0", "@types/express": "^5.0.0", - "express": "^4.21.2" + "express": "^4.21.2", + "zod-to-json-schema": "^3.24.0", + "zod": "^3.24.2" } } diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index caaae98a..4eb0043a 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -14,6 +14,8 @@ import type { OrchestrationResponse, StreamOptions } from '@sap-ai-sdk/orchestration'; +import { z } from 'zod'; +import { zodToJsonSchema } from "zod-to-json-schema"; const logger = createLogger({ package: 'sample-code', @@ -501,6 +503,10 @@ export interface TranslationResponseType { * @returns The orchestration service response. */ export async function orchestrationResponseFormat(): Promise { + const translationSchema = z.object({ + language: z.string(), + translation: z.string() + }).strict(); const orchestrationClient = new OrchestrationClient({ llm, templating: { @@ -520,20 +526,7 @@ export async function orchestrationResponseFormat(): Promise Date: Thu, 13 Feb 2025 12:27:13 +0100 Subject: [PATCH 04/19] fix pnpm lock --- pnpm-lock.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15db943e..df6f4a1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,7 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -pnpmfileChecksum: fb3vh7gyjzvxzzal7fbygn3ogm +pnpmfileChecksum: sha256-7lht5Q+T9K1tkr5FYaoHEDBAtJqjkSrAs2jGbKMfTIY= importers: @@ -6146,8 +6146,8 @@ snapshots: '@typescript-eslint/parser': 8.22.0(eslint@9.20.1)(typescript@5.7.3) eslint: 9.20.1 eslint-config-prettier: 10.0.1(eslint@9.20.1) - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1) eslint-plugin-jsdoc: 50.6.3(eslint@9.20.1) eslint-plugin-prettier: 5.2.3(@types/eslint@8.56.10)(eslint-config-prettier@10.0.1(eslint@9.20.1))(eslint@9.20.1)(prettier@3.5.0) eslint-plugin-regex: 1.10.0(eslint@9.20.1) @@ -7616,7 +7616,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) @@ -7628,22 +7628,22 @@ snapshots: is-glob: 4.0.3 stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1))(eslint@9.20.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.22.0(eslint@9.20.1)(typescript@5.7.3) eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -7654,7 +7654,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.1))(eslint@9.20.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.22.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1))(eslint@9.20.1))(eslint@9.20.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 8d52fcde014bc3866d8f637d6d69844c1b193d30 Mon Sep 17 00:00:00 2001 From: cloud-sdk-js Date: Thu, 13 Feb 2025 11:28:20 +0000 Subject: [PATCH 05/19] fix: Changes from lint --- sample-code/src/orchestration.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index 4eb0043a..53ab1ddb 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -7,6 +7,8 @@ import { buildAzureContentSafetyFilter } from '@sap-ai-sdk/orchestration'; import { createLogger } from '@sap-cloud-sdk/util'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; import type { LlmModuleConfig, OrchestrationStreamChunkResponse, @@ -14,8 +16,6 @@ import type { OrchestrationResponse, StreamOptions } from '@sap-ai-sdk/orchestration'; -import { z } from 'zod'; -import { zodToJsonSchema } from "zod-to-json-schema"; const logger = createLogger({ package: 'sample-code', @@ -503,10 +503,12 @@ export interface TranslationResponseType { * @returns The orchestration service response. */ export async function orchestrationResponseFormat(): Promise { - const translationSchema = z.object({ - language: z.string(), - translation: z.string() - }).strict(); + const translationSchema = z + .object({ + language: z.string(), + translation: z.string() + }) + .strict(); const orchestrationClient = new OrchestrationClient({ llm, templating: { From 75e325af5434a2fe4cea618c5974952524670bac Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Thu, 13 Feb 2025 15:50:27 +0100 Subject: [PATCH 06/19] update docs --- packages/orchestration/README.md | 53 +++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 34aab792..573626ff 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -109,7 +109,6 @@ Optionally, define `model_version` (default: `latest`) and `model_params` for cu Use the orchestration client with templating to pass a prompt containing placeholders that will be replaced with input parameters during a chat completion request. This allows for variations in the prompt based on the input parameters. -Set custom request configuration when calling `chatCompletion` function. ```ts import { OrchestrationClient } from '@sap-ai-sdk/orchestration'; @@ -131,28 +130,52 @@ const response = await orchestrationClient.chatCompletion({ }); const responseContent = response.getContent(); +const finishReason = response.getFinishReason(); +const tokenUsage = response.getTokenUsage(); ``` -`getContent()` is a convenience method that parses the response and returns the model's output as a string. +You can use the following convenience methods for handling chat completion responses: +- `getContent()`: parses the response and returns the model's output as a string. +- `getFinishReason()`: retrieves the finish_reason, explaining why the chat completion request stopped. +- `getTokenUsage()`: provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. -To retrieve the `finish_reason` for stopping the chat completion request, use the convenience method `getFinishReason()`: +#### Structured Outputs -```ts -const finishReason = response.getFinishReason(); -``` - -Use the `getTokenUsage()` convenience method to retrieve the token usage details of the chat completion request: +The `response_format` under `templating` guarantees that the model's output aligns with the JSON schemas specified by developers. +It is useful when the model is not calling a tool, but rather, responding to the user in a structured way. +By setting `strict: true`, the model ensures that its outputs conform precisely to the provided schema. ```ts -const tokenUsage = response.getTokenUsage(); - -console.log( - `Total tokens consumed by the request: ${tokenUsage.total_tokens}\n` + - `Input prompt tokens consumed: ${tokenUsage.prompt_tokens}\n` + - `Output text completion tokens consumed: ${tokenUsage.completion_tokens}\n` -); +templating: { + template: [ + { role: 'user', content: 'What is the capital of {{?country}}?' } + ], + response_format: { + type: 'json_schema', + json_schema: { + name: 'capital_response', + strict: true, + schema: { + type: 'object', + properties: { + country_name: { + type: "string", + description: "The name of the country provided by the user." + }, + capital: { + type: "string", + description: "The capital city of the country." + } + }, + required: ["country_name", "capital"] + } + } + } + } ``` +In addition to using JSON schema objects, a zod schema is also supported. + ### Prompt Registry Alternatively, prepared templates from the [Prompt Registry](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/prompt-registry) of SAP AI Core can be used instead of passing a template in the request. From 2fcdb2855f33851397bd2403ed1e946ac09aae6d Mon Sep 17 00:00:00 2001 From: cloud-sdk-js Date: Thu, 13 Feb 2025 14:51:31 +0000 Subject: [PATCH 07/19] fix: Changes from lint --- packages/orchestration/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 573626ff..bae9496c 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -135,6 +135,7 @@ const tokenUsage = response.getTokenUsage(); ``` You can use the following convenience methods for handling chat completion responses: + - `getContent()`: parses the response and returns the model's output as a string. - `getFinishReason()`: retrieves the finish_reason, explaining why the chat completion request stopped. - `getTokenUsage()`: provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. From e5b067d76fb8504526b35d3cb91e2d7ffaadc146 Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Thu, 13 Feb 2025 16:45:52 +0100 Subject: [PATCH 08/19] fix vale --- packages/orchestration/README.md | 2 +- styles/config/vocabularies/SAP/accept.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index bae9496c..d7cac198 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -175,7 +175,7 @@ templating: { } ``` -In addition to using JSON schema objects, a zod schema is also supported. +In addition to using JSON schema objects, a Zod schema is also supported. ### Prompt Registry diff --git a/styles/config/vocabularies/SAP/accept.txt b/styles/config/vocabularies/SAP/accept.txt index 4b7f8f25..7c969599 100644 --- a/styles/config/vocabularies/SAP/accept.txt +++ b/styles/config/vocabularies/SAP/accept.txt @@ -137,6 +137,7 @@ seldomly lookups CDS +[Zz]od llm's [Ll][Ll][Mm]'s \ No newline at end of file From ae9f26d95a14d3e0ad545ab1cf2d9614d5e5a5fa Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Fri, 14 Feb 2025 11:46:16 +0100 Subject: [PATCH 09/19] fix type name --- sample-code/src/index.ts | 2 +- sample-code/src/orchestration.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-code/src/index.ts b/sample-code/src/index.ts index 247bb246..0955d48f 100644 --- a/sample-code/src/index.ts +++ b/sample-code/src/index.ts @@ -19,7 +19,7 @@ export { orchestrationGroundingHelpSapCom, orchestrationChatCompletionImage, orchestrationResponseFormat, - TranslationResponseType, + TranslationResponse, chatCompletionStreamWithJsonModuleConfig, chatCompletionStream } from './orchestration.js'; diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index 53ab1ddb..5d720151 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -488,7 +488,7 @@ export async function orchestrationChatCompletionImage(): Promise { +export async function orchestrationResponseFormat(): Promise { const translationSchema = z .object({ language: z.string(), @@ -539,5 +539,5 @@ export async function orchestrationResponseFormat(): Promise Date: Fri, 14 Feb 2025 11:47:09 +0100 Subject: [PATCH 10/19] Apply suggestions from code review --- sample-code/src/orchestration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index 5d720151..fc94c7ab 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -499,8 +499,8 @@ export interface TranslationResponse { translation: string; } /** - * Ask about the image content using a template. - * @returns The orchestration service response. + * Ask the Llm to translate a text to a randomly chosen language and return a structured response. + * @returns Response that adheres to `TranslationResponse` type. */ export async function orchestrationResponseFormat(): Promise { const translationSchema = z From a1220a29728de93519be733c87634b2e01498dc5 Mon Sep 17 00:00:00 2001 From: Deeksha Sinha <88374536+deekshas8@users.noreply.github.com> Date: Fri, 14 Feb 2025 11:52:19 +0100 Subject: [PATCH 11/19] Update packages/orchestration/README.md Co-authored-by: Zhongpin Wang --- packages/orchestration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index d7cac198..f812f704 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -142,7 +142,7 @@ You can use the following convenience methods for handling chat completion respo #### Structured Outputs -The `response_format` under `templating` guarantees that the model's output aligns with the JSON schemas specified by developers. +Setting `response_format` under `templating` guarantees that the model's output aligns with the schema type specified by developers. It is useful when the model is not calling a tool, but rather, responding to the user in a structured way. By setting `strict: true`, the model ensures that its outputs conform precisely to the provided schema. From fd432e7653e3104985654daeb9edf06405666137 Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Fri, 14 Feb 2025 12:21:56 +0100 Subject: [PATCH 12/19] fix --- packages/orchestration/README.md | 5 +++-- sample-code/src/orchestration.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index f812f704..b3f75163 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -144,7 +144,8 @@ You can use the following convenience methods for handling chat completion respo Setting `response_format` under `templating` guarantees that the model's output aligns with the schema type specified by developers. It is useful when the model is not calling a tool, but rather, responding to the user in a structured way. -By setting `strict: true`, the model ensures that its outputs conform precisely to the provided schema. + +The example below demonstrates how to use `response_format` to return a JSON Schema, with `strict: true` ensuring the outputs conform precisely to the schema. ```ts templating: { @@ -175,7 +176,7 @@ templating: { } ``` -In addition to using JSON schema objects, a Zod schema is also supported. +The `json_schema` can also be initialized directly using a Zod schema. ### Prompt Registry diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index fc94c7ab..f727e093 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -534,10 +534,10 @@ export async function orchestrationResponseFormat(): Promise Date: Fri, 14 Feb 2025 12:56:34 +0100 Subject: [PATCH 13/19] Update packages/orchestration/README.md Co-authored-by: Zhongpin Wang --- packages/orchestration/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index b3f75163..918b40de 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -136,9 +136,9 @@ const tokenUsage = response.getTokenUsage(); You can use the following convenience methods for handling chat completion responses: -- `getContent()`: parses the response and returns the model's output as a string. -- `getFinishReason()`: retrieves the finish_reason, explaining why the chat completion request stopped. -- `getTokenUsage()`: provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. +- `getContent()` method parses the response and returns the model's output as a string. +- `getFinishReason()` method retrieves the `finish_reason` explaining why chat completion request stopped. +- `getTokenUsage()` method provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. #### Structured Outputs From 0867d32bd85e22e134aea1554be7c18dc4055f4c Mon Sep 17 00:00:00 2001 From: deekshas8 Date: Fri, 14 Feb 2025 16:56:36 +0100 Subject: [PATCH 14/19] add zod docs --- packages/orchestration/README.md | 17 ++++++++++++++++- sample-code/src/orchestration.ts | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 918b40de..d44e5b32 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -175,8 +175,23 @@ templating: { } } ``` +You can also initialize `json_schema` using a Zod schema, as shown below: -The `json_schema` can also be initialized directly using a Zod schema. +```ts +const countryCapitalSchema = z.object({ + country_name: z.string().describe('The name of the country provided by the user.'), + capital: z.string().describe('The capital city of the country.') + }).strict(); + +response_format: { + type: 'json_schema', + json_schema: { + name: 'capital_response', + strict: true, + schema: zodToJsonSchema(countryCapitalSchema) + } +} +``` ### Prompt Registry diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index f727e093..d799fc14 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -505,8 +505,8 @@ export interface TranslationResponse { export async function orchestrationResponseFormat(): Promise { const translationSchema = z .object({ - language: z.string(), - translation: z.string() + language: z.string().describe('The language of the translation, randomly chosen by the LLM.'), + translation: z.string().describe('The translation of the input sentence.') }) .strict(); const orchestrationClient = new OrchestrationClient({ From 51c81abeb5ff7d6685d6c0f1388b41b9fd044bfc Mon Sep 17 00:00:00 2001 From: cloud-sdk-js Date: Fri, 14 Feb 2025 15:57:36 +0000 Subject: [PATCH 15/19] fix: Changes from lint --- packages/orchestration/README.md | 1 + sample-code/src/orchestration.ts | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index d44e5b32..455b81c7 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -175,6 +175,7 @@ templating: { } } ``` + You can also initialize `json_schema` using a Zod schema, as shown below: ```ts diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index d799fc14..625ec2e0 100644 --- a/sample-code/src/orchestration.ts +++ b/sample-code/src/orchestration.ts @@ -505,7 +505,11 @@ export interface TranslationResponse { export async function orchestrationResponseFormat(): Promise { const translationSchema = z .object({ - language: z.string().describe('The language of the translation, randomly chosen by the LLM.'), + language: z + .string() + .describe( + 'The language of the translation, randomly chosen by the LLM.' + ), translation: z.string().describe('The translation of the input sentence.') }) .strict(); From 06dc79764b29612e581ceba09a5feca1f9402062 Mon Sep 17 00:00:00 2001 From: Deeksha Sinha <88374536+deekshas8@users.noreply.github.com> Date: Mon, 17 Feb 2025 13:57:47 +0100 Subject: [PATCH 16/19] Update sample-code/src/index.ts --- sample-code/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/sample-code/src/index.ts b/sample-code/src/index.ts index 0955d48f..53d14492 100644 --- a/sample-code/src/index.ts +++ b/sample-code/src/index.ts @@ -19,7 +19,6 @@ export { orchestrationGroundingHelpSapCom, orchestrationChatCompletionImage, orchestrationResponseFormat, - TranslationResponse, chatCompletionStreamWithJsonModuleConfig, chatCompletionStream } from './orchestration.js'; From 6c827c06349406f005ed2ad67d727c220d93df2c Mon Sep 17 00:00:00 2001 From: Deeksha Sinha <88374536+deekshas8@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:30:53 +0100 Subject: [PATCH 17/19] Apply suggestions from code review Co-authored-by: Tom Frenken <54979414+tomfrenken@users.noreply.github.com> --- packages/orchestration/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 455b81c7..e3f7202c 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -136,9 +136,9 @@ const tokenUsage = response.getTokenUsage(); You can use the following convenience methods for handling chat completion responses: -- `getContent()` method parses the response and returns the model's output as a string. -- `getFinishReason()` method retrieves the `finish_reason` explaining why chat completion request stopped. -- `getTokenUsage()` method provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. +- `getContent()` parses the response and returns the model's output as a string. +- `getFinishReason()` retrieves the `finish_reason` explaining why chat completion request stopped. +- `getTokenUsage()` provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. #### Structured Outputs From 19372cd338824e10b248c8bfe7f58b2268c573f1 Mon Sep 17 00:00:00 2001 From: Deeksha Sinha <88374536+deekshas8@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:32:27 +0100 Subject: [PATCH 18/19] Update packages/orchestration/README.md --- packages/orchestration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index e3f7202c..0048a204 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -138,7 +138,7 @@ You can use the following convenience methods for handling chat completion respo - `getContent()` parses the response and returns the model's output as a string. - `getFinishReason()` retrieves the `finish_reason` explaining why chat completion request stopped. -- `getTokenUsage()` provides token usage details, namely `total_tokens`, `prompt_tokens`, and `completion_tokens`. +- `getTokenUsage()` provides token usage details, including `total_tokens`, `prompt_tokens`, and `completion_tokens`. #### Structured Outputs From fe615bbcf0229e948439590bc5a915fd0bae10bb Mon Sep 17 00:00:00 2001 From: Deeksha Sinha <88374536+deekshas8@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:34:44 +0100 Subject: [PATCH 19/19] Apply suggestions from code review --- packages/orchestration/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 0048a204..b6e4446b 100644 --- a/packages/orchestration/README.md +++ b/packages/orchestration/README.md @@ -180,8 +180,8 @@ You can also initialize `json_schema` using a Zod schema, as shown below: ```ts const countryCapitalSchema = z.object({ - country_name: z.string().describe('The name of the country provided by the user.'), - capital: z.string().describe('The capital city of the country.') + country_name: z.string(), + capital: z.string() }).strict(); response_format: {