Skip to content

Commit

Permalink
Work-around for 'Cannot convert undefined or null to object' when sen…
Browse files Browse the repository at this point in the history
…ding to Skill
  • Loading branch information
Tracy Boehrer committed Dec 26, 2023
1 parent a51e3c6 commit 65f92e1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 3 deletions.
12 changes: 12 additions & 0 deletions libraries/botbuilder-core/src/botState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ export class BotState implements PropertyManager {
return this.storage.write(changes).then(() => {
// Update change hash and cache
cached.hash = calculateChangeHash(state);

// why does this happen in JS? It doesn't in the other platforms.
// the issue is related to 'skipProperties', which nulls out those
// properties in 'cached'. This replaces the state in 'context',
// and could change the values of references.
//
// Should 'calculateChangeHash' also consider the skipProperties?
//
// See SkillDialog.sendToSkill
//
// At any rate, would not expect saveChanges to alter the members
// of a class in use.
context.turnState.set(this.stateKey, cached);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class BeginSkill extends SkillDialog implements BeginSkillConfiguration {
// Store the initialized dialogOptions in state so we can restore these values when the dialog is resumed.
dc.activeDialog.state[this._dialogOptionsStateKey] = this.dialogOptions;
const skipProperties = dc.context.turnState.get(CACHED_BOT_STATE_SKIP_PROPERTIES_HANDLER_KEY);
const props: (keyof SkillDialogOptions)[] = ['conversationIdFactory', 'conversationState'];
const props: (keyof SkillDialogOptions)[] = ['conversationIdFactory', 'conversationState', 'skillClient'];
skipProperties(this._dialogOptionsStateKey, props);

// Get the activity to send to the skill.
Expand Down
13 changes: 11 additions & 2 deletions libraries/botbuilder-dialogs/src/skillDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,18 @@ export class SkillDialog extends Dialog<Partial<BeginSkillDialogOptions>> {
// Always save state before forwarding
// (the dialog stack won't get updated with the skillDialog and things won't work if you don't)
const skillInfo = this.dialogOptions.skill;

// this is to compensate for an undesirable side-effeft of saveChanges, which
// skips specific properties, which results in those properties being nulled out.
// after saveChanges, this.dialogOptions is missing some required values.
// this work`around allows this method to work, but 'interceptOAuthCards' (below)
// could encounter problems (not currently used by UHG).
const skillClient = this.dialogOptions.skillClient;
const conversationIdFactory = this.dialogOptions.conversationIdFactory;

await this.dialogOptions.conversationState.saveChanges(context, true);

const response = await this.dialogOptions.skillClient.postActivity<ExpectedReplies>(
const response = await skillClient.postActivity<ExpectedReplies>(
this.dialogOptions.botId,
skillInfo.appId,
skillInfo.skillEndpoint,
Expand Down Expand Up @@ -291,7 +300,7 @@ export class SkillDialog extends Dialog<Partial<BeginSkillDialogOptions>> {
console.log(
`SkillHandlerImpl.sendToSkill, deleteConversationReference skillConversationId=${skillConversationId}`
);
await this.dialogOptions.conversationIdFactory.deleteConversationReference(skillConversationId);
await conversationIdFactory.deleteConversationReference(skillConversationId);
} else if (
!sentInvokeResponses &&
(await this.interceptOAuthCards(context, activityFromSkill, this.dialogOptions.connectionName))
Expand Down

0 comments on commit 65f92e1

Please sign in to comment.