Skip to content

Commit a765744

Browse files
authored
Change action result to display as append block (#1425)
- Action result display content should be appended as block so that it can work with using `actionIO` within the action. Other display option can be access thru `actionIO` - Make sure the chat `generateResponse` and `lookupAndAnswer` doesn't display twice. - Rename the action result's `literalText` to `historyText` to indicate that the text is used for chat history. - Change `lookupAndAnswer` to return the resulting text in `historyText` as well along with the entities for used for chat history.
1 parent b1712fc commit a765744

File tree

13 files changed

+103
-112
lines changed

13 files changed

+103
-112
lines changed

ts/packages/agentSdk/src/action.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export type ActionResultActivityContext = Omit<
2121
> | null;
2222

2323
export type ActionResultSuccess = {
24-
literalText?: string | undefined;
25-
displayContent: DisplayContent;
24+
historyText?: string | undefined;
25+
displayContent: DisplayContent; // the display content to be appended with "block" mode
2626
entities: Entity[];
2727
resultEntity?: Entity | undefined;
2828
dynamicDisplayId?: string | undefined;

ts/packages/agentSdk/src/helpers/actionHelpers.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ import { DisplayMessageKind } from "../display.js";
1111
import { Entity } from "../memory.js";
1212

1313
export function createActionResultNoDisplay(
14-
literalText: string,
14+
historyText: string,
1515
entities?: Entity[] | undefined,
1616
): ActionResultSuccessNoDisplay {
1717
return {
18-
literalText,
18+
historyText,
1919
entities: entities ? entities : [],
2020
};
2121
}
2222

2323
export function createActionResult(
24-
literalText: string,
24+
displayAndHistoryText: string,
2525
options?:
2626
| {
2727
kind?: DisplayMessageKind;
@@ -39,7 +39,7 @@ export function createActionResult(
3939
: options;
4040

4141
return {
42-
literalText,
42+
historyText: displayAndHistoryText,
4343
entities: entities
4444
? Array.isArray(entities)
4545
? entities
@@ -48,31 +48,31 @@ export function createActionResult(
4848
displayContent: displayOptions
4949
? {
5050
type: "text",
51-
content: literalText,
51+
content: displayAndHistoryText,
5252
...displayOptions,
5353
}
54-
: literalText,
54+
: displayAndHistoryText,
5555
};
5656
}
5757

5858
export function createActionResultFromTextDisplay(
5959
displayText: string,
60-
literalText?: string,
60+
historyText?: string,
6161
): ActionResultSuccess {
6262
return {
63-
literalText,
63+
historyText,
6464
entities: [],
6565
displayContent: displayText,
6666
};
6767
}
6868

6969
export function createActionResultFromHtmlDisplay(
7070
displayText: string,
71-
literalText?: string,
71+
historyText?: string,
7272
entities?: Entity[] | undefined,
7373
): ActionResultSuccess {
7474
return {
75-
literalText,
75+
historyText,
7676
entities: entities ? entities : [],
7777
displayContent: {
7878
type: "html",
@@ -83,10 +83,10 @@ export function createActionResultFromHtmlDisplay(
8383

8484
export function createActionResultFromHtmlDisplayWithScript(
8585
displayText: string,
86-
literalText?: string,
86+
historyText?: string,
8787
): ActionResultSuccess {
8888
return {
89-
literalText,
89+
historyText,
9090
entities: [],
9191
displayContent: {
9292
type: "iframe",
@@ -104,13 +104,13 @@ export function createActionResultFromHtmlDisplayWithScript(
104104
*/
105105
export function createActionResultFromMarkdownDisplay(
106106
markdownText: string | string[],
107-
literalText?: string,
107+
historyText?: string,
108108
entities: Entity[] = [],
109109
resultEntity?: Entity,
110110
): ActionResultSuccess {
111111
return {
112-
literalText:
113-
literalText ??
112+
historyText:
113+
historyText ??
114114
(Array.isArray(markdownText)
115115
? markdownText.join("\n")
116116
: markdownText),

ts/packages/agents/browser/src/agent/actionHandler.mts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,7 +1779,7 @@ async function handleWebsiteAction(
17791779
);
17801780
return {
17811781
success: !statsResult.error,
1782-
result: statsResult.literalText || "Stats retrieved",
1782+
result: statsResult.historyText || "Stats retrieved",
17831783
error: statsResult.error,
17841784
};
17851785

@@ -1976,8 +1976,8 @@ async function handleWebsiteLibraryStats(
19761976

19771977
// Parse and format the response - extract text from ActionResult
19781978
let responseText = "";
1979-
if (statsResult.literalText) {
1980-
responseText = statsResult.literalText;
1979+
if (statsResult.historyText) {
1980+
responseText = statsResult.historyText;
19811981
} else if (statsResult.displayContent) {
19821982
// Handle different types of display content
19831983
if (typeof statsResult.displayContent === "string") {

ts/packages/agents/chat/src/chatResponseHandler.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010

1111
import { ActionContext, AppAgent, TypeAgentAction } from "@typeagent/agent-sdk";
1212
import {
13-
createActionResult,
1413
createActionResultFromHtmlDisplay,
1514
createActionResultNoDisplay,
1615
} from "@typeagent/agent-sdk/helpers/action";
@@ -63,8 +62,7 @@ async function handleChatResponse(
6362
console.log(JSON.stringify(chatAction, undefined, 2));
6463
switch (chatAction.actionName) {
6564
case "generateResponse": {
66-
return generateReponse(chatAction, context);
67-
break;
65+
return generateResponse(chatAction, context);
6866
}
6967

7068
case "showImageFile":
@@ -79,7 +77,7 @@ async function handleChatResponse(
7977
}
8078
}
8179

82-
async function generateReponse(
80+
async function generateResponse(
8381
generateResponseAction: GenerateResponseAction,
8482
context: ActionContext,
8583
) {
@@ -92,23 +90,29 @@ async function generateReponse(
9290
"Got generated text: " + generatedText.substring(0, 100) + "...",
9391
);
9492

95-
const needDisplay =
96-
context.streamingContext !== generatedText ||
97-
generateResponseAction.parameters.relatedFiles;
98-
let result;
99-
if (needDisplay) {
100-
if (generateResponseAction.parameters.relatedFiles) {
101-
result = createActionResultFromHtmlDisplay(
102-
`<div>${generatedText}</div><div class='chat-smallImage'>${await rehydrateImages(context, generateResponseAction.parameters.relatedFiles!)}</div>`,
103-
);
104-
} else {
105-
result = createActionResult(generatedText, true);
106-
}
107-
} else {
108-
result = createActionResultNoDisplay(generatedText);
93+
const streamingContext = context.streamingContext;
94+
context.streamingContext = undefined; // clear the streaming context
95+
if (streamingContext !== generatedText) {
96+
// Either we didn't stream, or we streamed a different text.
97+
// REVIEW: what happens to the speaking text that was streamed?
98+
context.actionIO.setDisplay({
99+
type: "text",
100+
content: generatedText,
101+
speak: streamingContext === undefined,
102+
});
109103
}
110104

111-
let entities = parameters.generatedTextEntities || [];
105+
// Add the related files.
106+
if (generateResponseAction.parameters.relatedFiles) {
107+
context.actionIO.appendDisplay(
108+
`<div class='chat-smallImage'>${await rehydrateImages(context, generateResponseAction.parameters.relatedFiles!)}</div>`,
109+
"block",
110+
);
111+
}
112+
113+
const result = createActionResultNoDisplay(generatedText);
114+
115+
const entities = parameters.generatedTextEntities || [];
112116
if (parameters.userRequestEntities !== undefined) {
113117
result.entities = parameters.userRequestEntities.concat(entities);
114118
}

ts/packages/agents/greeting/src/greetingCommandHandler.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { ChatModelWithStreaming, CompletionSettings, openai } from "aiclient";
1919
import { PromptSection, Result } from "typechat";
2020
import {
2121
displayError,
22-
displayResult,
2322
displayStatus,
2423
} from "@typeagent/agent-sdk/helpers/display";
2524
import {
@@ -153,7 +152,10 @@ export class GreetingCommandHandler implements CommandHandlerNoParams {
153152
context,
154153
)) as ActionResultSuccess;
155154

156-
displayResult(result.literalText!, context);
155+
context.actionIO.appendDisplay(
156+
result.displayContent,
157+
"block",
158+
);
157159
break;
158160

159161
// case "contextualGreetingAction":

ts/packages/agents/player/src/agent/playerHandlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ async function getPlayerDynamicDisplay(
280280
const status = await htmlStatus(context.agentContext.spotify);
281281
return {
282282
content:
283-
type === "html" ? status.displayContent : status.literalText!,
283+
type === "html" ? status.displayContent : status.historyText!,
284284

285285
nextRefreshMs: 1000,
286286
};

ts/packages/agents/player/src/client.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ async function htmlTrackNames(
223223

224224
const actionResult: ActionResult = {
225225
displayContent,
226-
literalText: "",
226+
historyText: "",
227227
entities: [],
228228
};
229229
let prevUrl = "";
@@ -279,7 +279,7 @@ async function htmlTrackNames(
279279
}
280280
}
281281
displayContent.content += "</ol></div>";
282-
actionResult.literalText =
282+
actionResult.historyText =
283283
"Updated the current track list with the numbered list of tracks on the screen";
284284
} else if (selectedTracks.length === 1) {
285285
const track = selectedTracks[0];
@@ -312,7 +312,7 @@ async function htmlTrackNames(
312312
const litArtists =
313313
litArtistsPrefix +
314314
track.artists.map((artist) => artist.name).join(", ");
315-
actionResult.literalText = `Now playing: ${track.name} from album ${track.album.name} with ${litArtists}`;
315+
actionResult.historyText = `Now playing: ${track.name} from album ${track.album.name} with ${litArtists}`;
316316
if (track.album.images.length > 0 && track.album.images[0].url) {
317317
displayContent.content = "<div class='track-list scroll_enabled'>";
318318
displayContent.content +=

ts/packages/agents/player/src/playback.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function htmlPlaybackStatus(
7373
}
7474
const pp = status.is_playing ? "" : "(paused)";
7575
const album = status.item.album.name;
76-
actionResult.literalText += `Now playing${pp}: ${status.item.name} from album ${album} with ${artists}`;
76+
actionResult.historyText += `Now playing${pp}: ${status.item.name} from album ${album} with ${artists}`;
7777
actionResult.entities.push({
7878
name: status.item.name,
7979
type: ["track"],
@@ -107,7 +107,7 @@ export async function htmlStatus(context: IClientContext) {
107107
content: "<div data-group='status'>Status...",
108108
};
109109
const actionResult: ActionResultSuccess = {
110-
literalText: "",
110+
historyText: "",
111111
entities: [],
112112
displayContent,
113113
};
@@ -117,10 +117,10 @@ export async function htmlStatus(context: IClientContext) {
117117
const aux = `Volume is ${activeDevice.volume_percent}%. ${status.shuffle_state ? "Shuffle on" : ""}`;
118118
displayContent.content += `<div>Active device: ${activeDevice.name} of type ${activeDevice.type}</div>`;
119119
displayContent.content += `<div>${aux}</div>`;
120-
actionResult.literalText += `\nActive device: ${activeDevice.name} of type ${activeDevice.type}\n${aux}`;
120+
actionResult.historyText += `\nActive device: ${activeDevice.name} of type ${activeDevice.type}\n${aux}`;
121121
} else {
122122
displayContent.content += "<div>Nothing playing.</div>";
123-
actionResult.literalText = "Nothing playing.";
123+
actionResult.historyText = "Nothing playing.";
124124
}
125125
displayContent.content += "</div>";
126126
actionResult.dynamicDisplayId = "status";

ts/packages/dispatcher/src/context/dispatcher/dispatcherAgent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ async function clarifyWithLookup(
182182

183183
if (
184184
lookupResult.error !== undefined ||
185-
lookupResult.literalText === undefined
185+
lookupResult.historyText === undefined
186186
) {
187187
return undefined;
188188
}
@@ -196,7 +196,7 @@ async function clarifyWithLookup(
196196

197197
history.promptSections.push({
198198
role: "assistant",
199-
content: lookupResult.literalText,
199+
content: lookupResult.historyText,
200200
});
201201

202202
const translationResult = await translateRequest(

ts/packages/dispatcher/src/context/memory.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ export function addActionResultToMemory(
201201

202202
addResultToMemory(
203203
context,
204-
result.literalText
205-
? result.literalText
204+
result.historyText
205+
? result.historyText
206206
: `Action ${getFullActionName(executableAction)} completed.`,
207207
schemaName,
208208
combinedEntities,
@@ -227,19 +227,19 @@ export async function lookupAndAnswerFromMemory(
227227
throw new Error(`Conversation memory search failed: ${result.message}`);
228228
}
229229

230-
const literalText: string[] = [];
230+
const historyText: string[] = [];
231231
for (const [searchResult, answer] of result.data) {
232232
debug("Conversation memory search result:", searchResult);
233233
if (answer.type === "Answered") {
234-
literalText.push(answer.answer!);
234+
historyText.push(answer.answer!);
235235
displayResult(answer.answer!, context);
236236
} else {
237-
literalText.push(answer.whyNoAnswer!);
237+
historyText.push(answer.whyNoAnswer!);
238238
displayError(answer.whyNoAnswer!, context);
239239
}
240240
}
241241
// TODO: how about entities?
242-
return literalText;
242+
return historyText;
243243
}
244244

245245
function ensureMemory(context: ActionContext<CommandHandlerContext>) {

0 commit comments

Comments
 (0)