Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3c85408
add getAllMessages() and sample code
shibeshduw Feb 12, 2025
8cc4c80
remove role check
shibeshduw Feb 13, 2025
0f9b0d4
Merge branch 'main' into orchestration-chat-ux
shibeshduw Feb 13, 2025
da97c53
fix: Changes from lint
Feb 13, 2025
3f1ba87
Merge remote-tracking branch 'origin/main' into orchestration-chat-ux
shibeshduw Feb 18, 2025
8961dab
refactor and documentation
shibeshduw Feb 18, 2025
6f32df9
remove handleSingleChatMessage
shibeshduw Feb 18, 2025
5351d7a
Merge branch 'main' into orchestration-chat-ux
shibeshduw Apr 23, 2025
24f1c61
typo
shibeshduw Apr 23, 2025
04c6b92
remove transformation
shibeshduw Apr 24, 2025
9a90542
spec update from orchestration/main
shibeshduw Apr 25, 2025
fc6ff91
small adjustment
shibeshduw Apr 25, 2025
1626d9f
fix test
shibeshduw Apr 25, 2025
0f34b38
adjust sample
shibeshduw Apr 25, 2025
bbecba0
Merge remote-tracking branch 'origin/main' into orchestration-chat-ux
shibeshduw Apr 25, 2025
85660fb
wip
shibeshduw Apr 25, 2025
fc70bd6
fix: Changes from lint
Apr 25, 2025
977a5a0
update readme
shibeshduw Apr 29, 2025
de04855
unit test for convenience
shibeshduw Apr 30, 2025
bf39470
Merge remote-tracking branch 'origin/main' into orchestration-chat-ux
shibeshduw Apr 30, 2025
8520d10
link issue
shibeshduw May 6, 2025
67197de
Merge remote-tracking branch 'origin/main' into orchestration-chat-ux
shibeshduw May 6, 2025
3a5de95
typo
shibeshduw May 6, 2025
b6c8b1e
changeset
shibeshduw May 6, 2025
46ce29d
Update .changeset/fuzzy-kids-divide.md
shibeshduw May 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/orchestration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@ const response = await orchestrationClient.chatCompletion({
const responseContent = response.getContent();
const finishReason = response.getFinishReason();
const tokenUsage = response.getTokenUsage();
const allMessages = response.getAllMessages();
```

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`.
- `getAllMessages()` parses the response and returns a list of all messages.

#### Structured Outputs

Expand Down
15 changes: 15 additions & 0 deletions packages/orchestration/src/orchestration-response.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ describe('OrchestrationResponse', () => {
});
});

it('should return a list of all messages', () => {
const messageList = orchestrationResponse.getAllMessages();

expect(messageList.length).toBe(2);
expect(messageList[0]).toMatchObject({
role: 'user',
content: expect.any(String)
});

expect(messageList[1]).toEqual({
role: 'assistant',
content: expect.any(String)
});
});

it('should return default choice index with convenience functions', () => {
expect(orchestrationResponse.getFinishReason()).toBe('stop');
expect(orchestrationResponse.getContent()).toBe(
Expand Down
56 changes: 55 additions & 1 deletion packages/orchestration/src/orchestration-response.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { HttpResponse } from '@sap-cloud-sdk/http-client';
import type {
CompletionPostResponse,
TokenUsage
TokenUsage,
ChatMessage,
SingleChatMessage,
MultiChatMessage,
ChatMessages
} from './client/api/schema/index.js';

/**
Expand Down Expand Up @@ -51,6 +55,56 @@ export class OrchestrationResponse {
return choice?.message?.content;
}

/**
* Messages that can be used for subsequent prompts as message history.
* @param choiceIndex - The index of the choice to parse.
* @returns A list of all messages.
*/
getAllMessages(choiceIndex = 0): ChatMessages {
const messages: ChatMessage[] = (
this.data.module_results.templating ?? []
).map(message =>
this.isMultiChatMessage(message)
? this.handleMultiChatMessage(message as MultiChatMessage)
: this.handleSingleChatMessage(message as SingleChatMessage)
);

const content = this.getChoices().find(c => c.index === choiceIndex)
?.message.content;
return content ? [...messages, { role: 'assistant', content }] : messages;
}

private handleSingleChatMessage(
singleChatMessage: SingleChatMessage
): ChatMessage {
return {
role: singleChatMessage.role,
content: singleChatMessage.content
};
}

private handleMultiChatMessage(
multiChatMessage: MultiChatMessage
): ChatMessage {
return {
role: multiChatMessage.role,
content: multiChatMessage.content
.map(content =>
content.type === 'text'
? content.text
: JSON.stringify({
url: content.image_url.url,
detail: content.image_url.detail
})
)
.join('\n')
};
}

private isMultiChatMessage(params: ChatMessage): params is MultiChatMessage {
return Array.isArray(params.content);
}

private getChoices() {
return this.data.orchestration_result.choices;
}
Expand Down
28 changes: 27 additions & 1 deletion sample-code/src/orchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import type {
OrchestrationStreamChunkResponse,
OrchestrationStreamResponse,
OrchestrationResponse,
StreamOptions
StreamOptions,
TemplatingChatMessage
} from '@sap-ai-sdk/orchestration';

const logger = createLogger({
Expand Down Expand Up @@ -142,6 +143,31 @@ export async function orchestrationTemplating(): Promise<OrchestrationResponse>
});
}

/**
* Chat request to OpenAI through the Orchestration service using message history.
* @returns The orchestration service response.
*/
export async function orchestrationMessagesHistory(): Promise<OrchestrationResponse> {
const orchestrationClient = (messages: TemplatingChatMessage) =>
new OrchestrationClient({
llm,
templating: {
template: messages
}
});

const firstResponse = await orchestrationClient([
{ role: 'user', content: 'What is the capital of France?' }
]).chatCompletion();

// User can then ask a follow-up question
const nextResponse = await orchestrationClient([
{ role: 'user', content: 'Are you sure?' }
]).chatCompletion({ messagesHistory: firstResponse.getAllMessages() });

return nextResponse;
}

/**
* Use a template stored in the prompt registry.
* @returns The orchestration service response.
Expand Down
2 changes: 2 additions & 0 deletions sample-code/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
orchestrationGroundingHelpSapCom,
orchestrationMaskGroundingInput,
orchestrationPromptRegistry,
orchestrationMessagesHistory,
orchestrationResponseFormat
} from './orchestration.js';
import {
Expand Down Expand Up @@ -257,6 +258,7 @@ app.get('/orchestration/:sampleCase', async (req, res) => {
simple: orchestrationChatCompletion,
template: orchestrationTemplating,
templateRef: orchestrationPromptRegistry,
messageHistory: orchestrationMessagesHistory,
inputFiltering: orchestrationInputFiltering,
outputFiltering: orchestrationOutputFiltering,
requestConfig: orchestrationRequestConfig,
Expand Down
16 changes: 15 additions & 1 deletion tests/type-tests/test/orchestration.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import type {
ChatModel,
GroundingModuleConfig,
LlmModelParams,
AzureContentSafetyFilterConfig
AzureContentSafetyFilterConfig,
ChatMessages
} from '@sap-ai-sdk/orchestration';

/**
Expand Down Expand Up @@ -80,6 +81,19 @@ expectType<TokenUsage>(
).getTokenUsage()
);

expectType<ChatMessages>(
(
await new OrchestrationClient({
templating: {
template: [{ role: 'user', content: 'Hello!' }]
},
llm: {
model_name: 'gpt-35-turbo-16k'
}
}).chatCompletion()
).getAllMessages()
);

expectType<Promise<OrchestrationResponse>>(
new OrchestrationClient(
{
Expand Down
Loading