Skip to content

Commit fc48bff

Browse files
authored
[JS] fix: Citations where context was being dropped in OpenAIModel.ts (#2136)
## Linked issues closes: #2131 closes: #2080 ## Details - Change the abstract length to 477, in the rare case where the word clips at >477 but <480, then adds ellipses - `OpenAIModel`: re-add message context so it is not being dropped from `ToolsAugmentation` changes. This now means citations are being rendered as expected. <img width="862" alt="image" src="https://github.com/user-attachments/assets/307e9f9f-251c-4220-aa87-1268e92057ac"> ## Attestation Checklist - [x] My code follows the style guidelines of this project - I have checked for/fixed spelling, linting, and other errors - I have commented my code for clarity - I have made corresponding changes to the documentation (updating the doc strings in the code is sufficient) - My changes generate no new warnings - I have added tests that validates my changes, and provides sufficient test coverage. I have tested with: - Local testing - E2E testing in Teams - New and existing unit tests pass locally with my changes ### Additional information > Feel free to add other relevant information below --------- Co-authored-by: Corina Gum <>
1 parent e2ab8f3 commit fc48bff

File tree

28 files changed

+111
-49
lines changed

28 files changed

+111
-49
lines changed

dotnet/packages/Microsoft.TeamsAI/Microsoft.TeamsAI/AI/Action/DefaultActions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public async Task<string> SayCommandAsync([ActionTurnContext] ITurnContext turnC
105105
int i = 0;
106106
foreach (Citation citation in command.Response.Context.Citations)
107107
{
108-
string abs = CitationUtils.Snippet(citation.Content, 480);
108+
string abs = CitationUtils.Snippet(citation.Content, 477);
109109
if (isTeamsChannel)
110110
{
111111
content.Replace("\n", "<br>");

js/packages/teams-ai/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
"main": "./lib/index.js",
2626
"types": "./lib/index.d.ts",
2727
"peerDependencies": {
28-
"botbuilder": "^4.23.0",
29-
"openai": "^4.61.0"
28+
"botbuilder": "^4.23.1",
29+
"openai": "^4.68.2"
3030
},
3131
"dependencies": {
3232
"@azure/openai-assistants": "1.0.0-beta.6",
3333
"@azure/msal-node": "^2.15.0",
3434
"axios": "^1.7.5",
3535
"botbuilder-dialogs": "^4.23.1",
36-
"botframework-connector": "^4.23.0",
37-
"botframework-schema": "^4.23.0",
38-
"botframework-streaming": "^4.23.0",
36+
"botframework-connector": "^4.23.1",
37+
"botframework-schema": "^4.23.1",
38+
"botframework-streaming": "^4.23.1",
3939
"gpt-tokenizer": "^2.5.1",
4040
"json-colorizer": "^2.2.2",
4141
"jsonschema": "1.4.1",

js/packages/teams-ai/src/actions/SayCommand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function sayCommand<TState extends TurnState = TurnState>(feedbackLoopEna
4141
appearance: {
4242
'@type': 'DigitalDocument',
4343
name: citation.title || `Document #${i + 1}`,
44-
abstract: Utilities.snippet(citation.content, 480)
44+
abstract: Utilities.snippet(citation.content, 477)
4545
}
4646
};
4747

js/packages/teams-ai/src/models/OpenAIModel.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/// <reference types="mocha" />
2+
13
import { strict as assert } from 'assert';
24
import sinon from 'sinon';
35
import { OpenAIModel } from './OpenAIModel';
@@ -87,4 +89,56 @@ describe('OpenAIModel', () => {
8789
)
8890
);
8991
});
92+
93+
it('should handle citations in the context', async () => {
94+
const model = new OpenAIModel({
95+
apiKey: 'test-api-key',
96+
endpoint: 'https://test-endpoint.com',
97+
defaultModel: 'gpt-3.5-turbo'
98+
});
99+
100+
const mockResponse = {
101+
choices: [{
102+
message: {
103+
role: 'assistant',
104+
content: 'Test response',
105+
context: {
106+
citations: [
107+
{
108+
content: 'Citation content',
109+
title: 'Citation title',
110+
url: 'https://citation.url'
111+
}
112+
]
113+
}
114+
}
115+
}]
116+
};
117+
118+
// Mock the API call
119+
sinon.stub(model['_client'].chat.completions, 'create').resolves(mockResponse as any);
120+
121+
// Mock necessary parameters for completePrompt method
122+
const context: any = {};
123+
const memory: any = { getValue: () => ({}) };
124+
const functions: any = {};
125+
const tokenizer: any = {};
126+
const template: any = {
127+
config: { completion: {} },
128+
prompt: { renderAsMessages: async () => ({ output: [] }) }
129+
};
130+
131+
const result = await model.completePrompt(context, memory, functions, tokenizer, template);
132+
133+
assert.equal(result.status, 'success');
134+
assert.equal(result.message?.role, 'assistant');
135+
assert.equal(result.message?.content, 'Test response');
136+
assert.deepEqual(result.message?.context?.citations, [
137+
{
138+
content: 'Citation content',
139+
title: 'Citation title',
140+
url: 'https://citation.url'
141+
}
142+
]);
143+
});
90144
});

js/packages/teams-ai/src/models/OpenAIModel.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -375,16 +375,18 @@ export class OpenAIModel implements PromptCompletionModel {
375375
}
376376
// Handle tool calls
377377
if (delta.tool_calls) {
378-
message.action_calls = delta.tool_calls.map((toolCall) => {
379-
return {
380-
id: toolCall.id,
381-
function: {
382-
name: toolCall.function!.name,
383-
arguments: toolCall.function!.arguments
384-
},
385-
type: toolCall.type
386-
} as ActionCall;
387-
});
378+
message.action_calls = delta.tool_calls.map(
379+
(toolCall: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall) => {
380+
return {
381+
id: toolCall.id,
382+
function: {
383+
name: toolCall.function!.name,
384+
arguments: toolCall.function!.arguments
385+
},
386+
type: toolCall.type
387+
} as ActionCall;
388+
}
389+
);
388390
}
389391

390392
// Signal chunk received
@@ -400,8 +402,19 @@ export class OpenAIModel implements PromptCompletionModel {
400402
console.log(Colorize.value('duration', Date.now() - startTime, 'ms'));
401403
}
402404
} else {
403-
const actionCalls: ActionCall[] = [];
404405
const responseMessage = (completion as ChatCompletion).choices![0].message;
406+
message = {
407+
role: responseMessage.role,
408+
content: responseMessage.content ?? ''
409+
};
410+
411+
// Preserve message context if there is any
412+
const messageWithContext = responseMessage as Message<string>;
413+
414+
if (messageWithContext.context) {
415+
message.context = messageWithContext.context;
416+
}
417+
const actionCalls: ActionCall[] = [];
405418
const isToolsAugmentation =
406419
template.config.augmentation && template.config.augmentation?.augmentation_type == 'tools';
407420

@@ -418,16 +431,11 @@ export class OpenAIModel implements PromptCompletionModel {
418431
});
419432
}
420433
}
421-
// Log the generated response
422-
message = {
423-
role: responseMessage.role,
424-
content: responseMessage.content ?? ''
425-
};
426-
427434
if (actionCalls.length > 0) {
428435
message.action_calls = actionCalls;
429436
}
430437

438+
// Log the generated response
431439
if (this.options.logRequests) {
432440
console.log(Colorize.title('CHAT RESPONSE:'));
433441
console.log(Colorize.value('duration', Date.now() - startTime, 'ms'));

js/samples/01.getting-started/a.echoBot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@microsoft/teams-ai": "~1.5.2",
2626
"botbuilder": "^4.23.1",
2727
"dotenv": "^16.4.5",
28-
"openai": "4.61.0",
28+
"openai": "4.68.2",
2929
"replace": "~1.2.0",
3030
"restify": "~11.1.0"
3131
},

js/samples/02.teams-features/a.messageExtensions.searchCommand/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"axios": "^1.7.5",
2424
"botbuilder": "^4.23.1",
2525
"dotenv": "^16.4.5",
26-
"openai": "4.61.0",
26+
"openai": "4.68.2",
2727
"replace": "~1.2.0",
2828
"restify": "~11.1.0"
2929
},

js/samples/02.teams-features/b.adaptiveCards.typeAheadBot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"axios": "^1.7.5",
2727
"botbuilder": "^4.23.1",
2828
"dotenv": "^16.4.5",
29-
"openai": "4.61.0",
29+
"openai": "4.68.2",
3030
"replace": "~1.2.0",
3131
"restify": "~11.1.0"
3232
},

js/samples/03.ai-concepts/a.twentyQuestions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"@microsoft/teams-ai": "~1.5.2",
2525
"botbuilder": "^4.23.1",
2626
"dotenv": "^16.4.5",
27-
"openai": "4.61.0",
27+
"openai": "4.68.2",
2828
"replace": "~1.2.0",
2929
"restify": "~11.1.0"
3030
},

js/samples/03.ai-concepts/b.AI-messageExtensions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"botbuilder": "^4.23.1",
2323
"@microsoft/teams-ai": "~1.5.2",
2424
"dotenv": "^16.4.5",
25-
"openai": "4.61.0",
25+
"openai": "4.68.2",
2626
"replace": "~1.2.0",
2727
"restify": "~11.1.0"
2828
},

0 commit comments

Comments
 (0)