diff --git a/packages/orchestration/README.md b/packages/orchestration/README.md index 34aab7925..b6e4446b3 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,26 +130,68 @@ 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 chat completion request stopped. +- `getTokenUsage()` provides token usage details, including `total_tokens`, `prompt_tokens`, and `completion_tokens`. + +#### Structured Outputs + +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. -To retrieve the `finish_reason` for stopping the chat completion request, use the convenience method `getFinishReason()`: +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 -const finishReason = response.getFinishReason(); +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"] + } + } + } + } ``` -Use the `getTokenUsage()` convenience method to retrieve the token usage details of the chat completion request: +You can also initialize `json_schema` using a Zod schema, as shown below: ```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` -); +const countryCapitalSchema = z.object({ + country_name: z.string(), + capital: z.string() + }).strict(); + +response_format: { + type: 'json_schema', + json_schema: { + name: 'capital_response', + strict: true, + schema: zodToJsonSchema(countryCapitalSchema) + } +} ``` ### Prompt Registry diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 757e1e11c..1d0b0bd3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -215,10 +215,10 @@ importers: dependencies: '@langchain/core': specifier: 0.3.40 - version: 0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) + version: 0.3.40(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.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1))) + version: 0.1.0(@langchain/core@0.3.40(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.40(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.40(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: @@ -291,19 +297,19 @@ importers: version: 0.1.0(@langchain/core@0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2))) '@sap-ai-sdk/ai-api': specifier: canary - version: 1.8.1-20250217013122.0 + version: 1.7.1-20250211013110.0 '@sap-ai-sdk/document-grounding': specifier: canary - version: 1.8.1-20250217013122.0 + version: 1.7.1-20250211013110.0 '@sap-ai-sdk/foundation-models': specifier: canary - version: 1.8.1-20250217013122.0 + version: 1.7.1-20250211013110.0 '@sap-ai-sdk/langchain': specifier: canary - version: 1.8.1-20250217013122.0(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(zod@3.24.2) + version: 1.7.1-20250211013110.0(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(zod@3.24.2) '@sap-ai-sdk/orchestration': specifier: canary - version: 1.8.1-20250217013122.0 + version: 1.7.1-20250211013110.0 '@sap-cloud-sdk/util': specifier: ^3.26.0 version: 3.26.0 @@ -1086,6 +1092,10 @@ packages: '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@langchain/core@0.3.36': + resolution: {integrity: sha512-lOS6f5o2MarjGPomHPhzde9xI3lZW2NIOEdCv0dvjb1ZChWhwXWHtAMHSZmuSB53ySzDWAMkimimHd+Yqz5MwQ==} + engines: {node: '>=18'} + '@langchain/core@0.3.40': resolution: {integrity: sha512-RGhJOTzJv6H+3veBAnDlH2KXuZ68CXMEg6B6DPTzL3IGDyd+vLxXG4FIttzUwjdeQKjrrFBwlXpJDl7bkoApzQ==} engines: {node: '>=18'} @@ -1152,23 +1162,23 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sap-ai-sdk/ai-api@1.8.1-20250217013122.0': - resolution: {integrity: sha512-tkbssRcLx9DcYl84BMbW00wSWBTOlgSAp1KwhUxOqJSRpgFhXuKKTFIGtx4ePsHtTECMHLMTDAH4GFSKh0bj+w==} + '@sap-ai-sdk/ai-api@1.7.1-20250211013110.0': + resolution: {integrity: sha512-pFAqRq+VCs5RDT1ojIMZXQCSPKrqUraRci9d/qzonY7NCANX7q1yHx6MQWrz94yLp+fv8BFCctgVlzkUFghBhQ==} - '@sap-ai-sdk/core@1.8.1-20250217013122.0': - resolution: {integrity: sha512-6kyIjmjqwW6wa0AE9pcrwQF90j8MvUMdkB9kEDQ0pRpTEmhbZQ9z9VCoaINiGP6pt+7kzn2D5ne8LN9+VForWg==} + '@sap-ai-sdk/core@1.7.1-20250211013110.0': + resolution: {integrity: sha512-+zwCyOVnNCSDFUd2lShLbcFJ1mZC7hZJsrimElU/q+PxOAlxkgdH5vRt9dzwvos2+ADE3lqaO0GWXT12uip+uw==} - '@sap-ai-sdk/document-grounding@1.8.1-20250217013122.0': - resolution: {integrity: sha512-KMvE9WDaCNgHiM0XGfbB0wqr6qr4/kuKgkqd4Rn92IAfz6aBzDepwO/uSCzHFlURbq4/XrThM1219lZfuDLdDg==} + '@sap-ai-sdk/document-grounding@1.7.1-20250211013110.0': + resolution: {integrity: sha512-xPCquEcz+sBAkdcyX1F5ZV+eJXY5lz8dQiyQ3TYZJXThXTrzhsnS3oOOyWcK29BN0Yr/+tmorMeOzpnwMsdwxw==} - '@sap-ai-sdk/foundation-models@1.8.1-20250217013122.0': - resolution: {integrity: sha512-GKI/NzcxEIKUoGpz13/G33JliSnkh5IDRaHFPFewbU0k+48cIm/W92Qr4S+W9LZmC80mpHh0BKqNaeMA90UevQ==} + '@sap-ai-sdk/foundation-models@1.7.1-20250211013110.0': + resolution: {integrity: sha512-bKtbXrsOOswvgEN/WDHEKo0qYPLo42S1NS2CADSOkueUJ3+RKHUwCP5g56jWmssOUZ4oQp5owp5jILeboQ1MRg==} - '@sap-ai-sdk/langchain@1.8.1-20250217013122.0': - resolution: {integrity: sha512-7FbCNrp9pp61M1SOrQoxgVof6bxvnNZkXLBoyNKh+etNMPzWX6Bq0dHHmAbCAiPjijD+7zj9HlgJP2vA52XAHA==} + '@sap-ai-sdk/langchain@1.7.1-20250211013110.0': + resolution: {integrity: sha512-CKXmOhmnOlUrbsoF21emvJQM+Bjm2l1nQJ/MNzozgXCyEMK/w8zQZiVZUK4mRYnmgIEDYITq6MSAAuUChmKVzQ==} - '@sap-ai-sdk/orchestration@1.8.1-20250217013122.0': - resolution: {integrity: sha512-9QQMPqFcDnyUIV82fEMyzQMoQ/lBKZH2d4CaNbZ8Wflv9W3AttUBNQPvq1FJmw5KJquLmbdPVqH4a38D1pzGHw==} + '@sap-ai-sdk/orchestration@1.7.1-20250211013110.0': + resolution: {integrity: sha512-oTAJNMNweZHQ8LQcHpIlW339NRk5GUaXupHP/kH1mTmxeO0XnNdSH9gGo8PownVaSbziLX/AU3CdD9isP/6KHA==} '@sap-cloud-sdk/connectivity@3.26.0': resolution: {integrity: sha512-hEFASuLnpky4tOgwcHXOD2VjH+pR2nMWFVfjfRJno3vKKMFZ9kcrPi8MDyjMPypxJVmVtXdh8WTPjsxJoOCxVQ==} @@ -1399,8 +1409,8 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@18.19.76': - resolution: {integrity: sha512-yvR7Q9LdPz2vGpmpJX5LolrgRdWvB67MJKDPSgIIzpFbaf9a1j/f5DnLp5VDyHGMR0QZHlTr1afsD87QCXFHKw==} + '@types/node@18.19.75': + resolution: {integrity: sha512-UIksWtThob6ZVSyxcOqCLOUNg/dyO1Qvx4McgeuhrEtHTLFTf7BBhEazaE4K806FGTPtzd/2sE90qn4fVr7cyw==} '@types/node@20.17.19': resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} @@ -4872,9 +4882,6 @@ packages: peerDependencies: zod: ^3.24.1 - zod@3.24.1: - resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} - zod@3.24.2: resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} @@ -5919,14 +5926,14 @@ snapshots: '@jsdevtools/ono@7.1.3': {} - '@langchain/core@0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1))': + '@langchain/core@0.3.36(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 @@ -5953,17 +5960,6 @@ snapshots: transitivePeerDependencies: - openai - '@langchain/openai@0.4.3(@langchain/core@0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))(ws@8.18.0)': - dependencies: - '@langchain/core': 0.3.40(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.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))(ws@8.18.0)': dependencies: '@langchain/core': 0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -5975,11 +5971,6 @@ snapshots: - encoding - ws - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1)))': - dependencies: - '@langchain/core': 0.3.40(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.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)))': dependencies: '@langchain/core': 0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -6060,15 +6051,15 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@sap-ai-sdk/ai-api@1.8.1-20250217013122.0': + '@sap-ai-sdk/ai-api@1.7.1-20250211013110.0': dependencies: - '@sap-ai-sdk/core': 1.8.1-20250217013122.0 + '@sap-ai-sdk/core': 1.7.1-20250211013110.0 '@sap-cloud-sdk/connectivity': 3.26.0 transitivePeerDependencies: - debug - supports-color - '@sap-ai-sdk/core@1.8.1-20250217013122.0': + '@sap-ai-sdk/core@1.7.1-20250211013110.0': dependencies: '@sap-cloud-sdk/connectivity': 3.26.0 '@sap-cloud-sdk/http-client': 3.26.0 @@ -6078,17 +6069,17 @@ snapshots: - debug - supports-color - '@sap-ai-sdk/document-grounding@1.8.1-20250217013122.0': + '@sap-ai-sdk/document-grounding@1.7.1-20250211013110.0': dependencies: - '@sap-ai-sdk/core': 1.8.1-20250217013122.0 + '@sap-ai-sdk/core': 1.7.1-20250211013110.0 transitivePeerDependencies: - debug - supports-color - '@sap-ai-sdk/foundation-models@1.8.1-20250217013122.0': + '@sap-ai-sdk/foundation-models@1.7.1-20250211013110.0': dependencies: - '@sap-ai-sdk/ai-api': 1.8.1-20250217013122.0 - '@sap-ai-sdk/core': 1.8.1-20250217013122.0 + '@sap-ai-sdk/ai-api': 1.7.1-20250211013110.0 + '@sap-ai-sdk/core': 1.7.1-20250211013110.0 '@sap-cloud-sdk/connectivity': 3.26.0 '@sap-cloud-sdk/http-client': 3.26.0 '@sap-cloud-sdk/util': 3.26.0 @@ -6096,12 +6087,12 @@ snapshots: - debug - supports-color - '@sap-ai-sdk/langchain@1.8.1-20250217013122.0(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(zod@3.24.2)': + '@sap-ai-sdk/langchain@1.7.1-20250211013110.0(openai@4.83.0(ws@8.18.0)(zod@3.24.2))(zod@3.24.2)': dependencies: - '@langchain/core': 0.3.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) - '@sap-ai-sdk/ai-api': 1.8.1-20250217013122.0 - '@sap-ai-sdk/core': 1.8.1-20250217013122.0 - '@sap-ai-sdk/foundation-models': 1.8.1-20250217013122.0 + '@langchain/core': 0.3.36(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) + '@sap-ai-sdk/ai-api': 1.7.1-20250211013110.0 + '@sap-ai-sdk/core': 1.7.1-20250211013110.0 + '@sap-ai-sdk/foundation-models': 1.7.1-20250211013110.0 '@sap-cloud-sdk/connectivity': 3.26.0 uuid: 11.0.5 zod-to-json-schema: 3.24.1(zod@3.24.2) @@ -6111,10 +6102,10 @@ snapshots: - supports-color - zod - '@sap-ai-sdk/orchestration@1.8.1-20250217013122.0': + '@sap-ai-sdk/orchestration@1.7.1-20250211013110.0': dependencies: - '@sap-ai-sdk/ai-api': 1.8.1-20250217013122.0 - '@sap-ai-sdk/core': 1.8.1-20250217013122.0 + '@sap-ai-sdk/ai-api': 1.7.1-20250211013110.0 + '@sap-ai-sdk/core': 1.7.1-20250211013110.0 '@sap-cloud-sdk/util': 3.26.0 transitivePeerDependencies: - debug @@ -6141,7 +6132,7 @@ snapshots: 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-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) 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.1) eslint-plugin-regex: 1.10.0(eslint@9.20.1) @@ -6487,7 +6478,7 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@18.19.76': + '@types/node@18.19.75': dependencies: undici-types: 5.26.5 @@ -7622,7 +7613,7 @@ 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 @@ -7637,7 +7628,7 @@ snapshots: 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 @@ -9008,30 +8999,6 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.15(@langchain/core@0.3.40(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.40(openai@4.83.0(ws@8.18.0)(zod@3.24.1)) - '@langchain/openai': 0.4.3(@langchain/core@0.3.40(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.40(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.40(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.40(openai@4.83.0(ws@8.18.0)(zod@3.24.2)) @@ -9045,8 +9012,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 @@ -9056,18 +9023,6 @@ snapshots: - openai - ws - langsmith@0.3.7(openai@4.83.0(ws@8.18.0)(zod@3.24.1)): - dependencies: - '@types/uuid': 10.0.0 - chalk: 4.1.2 - console-table-printer: 2.12.1 - p-queue: 6.6.2 - p-retry: 4.6.2 - semver: 7.7.1 - uuid: 10.0.0 - optionalDependencies: - 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 @@ -9427,25 +9382,9 @@ snapshots: dependencies: mimic-fn: 2.1.0 - openai@4.83.0(ws@8.18.0)(zod@3.24.1): - dependencies: - '@types/node': 18.19.76 - '@types/node-fetch': 2.6.12 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0 - optionalDependencies: - ws: 8.18.0 - zod: 3.24.1 - transitivePeerDependencies: - - encoding - optional: true - openai@4.83.0(ws@8.18.0)(zod@3.24.2): dependencies: - '@types/node': 18.19.76 + '@types/node': 18.19.75 '@types/node-fetch': 2.6.12 abort-controller: 3.0.0 agentkeepalive: 4.6.0 @@ -10618,14 +10557,8 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.24.1(zod@3.24.1): - dependencies: - zod: 3.24.1 - zod-to-json-schema@3.24.1(zod@3.24.2): dependencies: zod: 3.24.2 - zod@3.24.1: {} - zod@3.24.2: {} diff --git a/sample-code/package.json b/sample-code/package.json index 7e992c327..0d7af3784 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/index.ts b/sample-code/src/index.ts index 3ed576332..53d14492e 100644 --- a/sample-code/src/index.ts +++ b/sample-code/src/index.ts @@ -18,6 +18,7 @@ export { orchestrationGroundingVector, orchestrationGroundingHelpSapCom, orchestrationChatCompletionImage, + orchestrationResponseFormat, chatCompletionStreamWithJsonModuleConfig, chatCompletionStream } from './orchestration.js'; diff --git a/sample-code/src/orchestration.ts b/sample-code/src/orchestration.ts index ba9511a8f..625ec2e04 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, @@ -482,3 +484,64 @@ export async function orchestrationChatCompletionImage(): Promise { + const translationSchema = z + .object({ + 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({ + 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, + schema: zodToJsonSchema(translationSchema) + } + } + } + }); + + const response = await orchestrationClient.chatCompletion({ + inputParams: { + input: 'Hello World! Why is this phrase so famous?' + } + }); + return JSON.parse(response.getContent()!) as TranslationResponse; +} diff --git a/sample-code/src/server.ts b/sample-code/src/server.ts index d9fe94cae..0c5e3f5f8 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,8 @@ 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/styles/config/vocabularies/SAP/accept.txt b/styles/config/vocabularies/SAP/accept.txt index 4b7f8f254..7c9695991 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 diff --git a/tests/e2e-tests/src/orchestration.test.ts b/tests/e2e-tests/src/orchestration.test.ts index 412590a5a..0440e4628 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());