Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor loadMessage function in room resource. #2047

Merged
merged 17 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
1 change: 1 addition & 0 deletions packages/host/app/components/matrix/room-message.gts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default class RoomMessage extends Component<Signature> {
@retryAction={{if @message.command (perform this.run) @retryAction}}
@isPending={{@isPending}}
data-test-boxel-message-from={{@message.author.name}}
data-test-boxel-message-instance-id={{@message.instanceId}}
...attributes
>
{{#if @message.command}}
Expand Down
2 changes: 1 addition & 1 deletion packages/host/app/components/matrix/room.gts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default class Room extends Component<Signature> {
@registerConversationScroller={{this.registerConversationScroller}}
@setScrollPosition={{this.setScrollPosition}}
>
{{#each this.messages as |message i|}}
{{#each this.messages key='eventId' as |message i|}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

<RoomMessage
@roomId={{@roomId}}
@message={{message}}
Expand Down
77 changes: 51 additions & 26 deletions packages/host/app/lib/matrix-classes/message-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ export default class MessageBuilder {
return errorMessage;
}

get formattedMessageForCommand() {
return `<p data-test-command-message class="command-message">${this.event.content.formatted_body}</p>`;
}

async buildMessage(): Promise<Message> {
buildMessage(): Message {
let { event } = this;
let message = this.coreMessageArgs;
message.errorMessage = this.errorMessage;
Expand All @@ -127,16 +123,17 @@ export default class MessageBuilder {
event.content.msgtype === APP_BOXEL_COMMAND_MSGTYPE &&
event.content.data.toolCall
) {
message.formattedMessage = this.formattedMessageForCommand;
message.command = await this.buildMessageCommand(message);
message.formattedMessage = formattedMessageForCommand(
event.content.formatted_body,
);
message.command = this.buildMessageCommand(message);
message.isStreamingFinished = true;
}
return message;
}

private async buildMessageCommand(message: Message) {
private buildMessageCommand(message: Message) {
let event = this.event as CommandEvent;
let command = event.content.data.toolCall;
let commandResultEvent = this.builderContext.events.find((e: any) => {
let r = e.content['m.relates_to'];
return (
Expand All @@ -147,23 +144,51 @@ export default class MessageBuilder {
r.event_id === this.builderContext.effectiveEventId)
);
}) as CommandResultEvent | undefined;
let status = (commandResultEvent?.content?.['m.relates_to']?.key ||
'ready') as CommandStatus;
let commandResultCardEventId =
commandResultEvent?.content?.msgtype ===
APP_BOXEL_COMMAND_RESULT_WITH_OUTPUT_MSGTYPE
? commandResultEvent.content.data.cardEventId
: undefined;
let messageCommand = new MessageCommand(

return buildMessageCommand({
effectiveEventId: this.builderContext.effectiveEventId,
owner: getOwner(this)!,
message,
command.id,
command.name,
command.arguments,
this.builderContext.effectiveEventId,
status,
commandResultCardEventId,
getOwner(this)!,
);
return messageCommand;
commandEvent: event,
commandResultEvent,
});
}
}

export function buildMessageCommand({
effectiveEventId,
commandEvent,
commandResultEvent,
message,
owner,
}: {
effectiveEventId: string;
commandEvent: CommandEvent;
commandResultEvent?: CommandResultEvent;
message: Message;
owner: Owner;
}) {
let status = (commandResultEvent?.content['m.relates_to']?.key ||
'ready') as CommandStatus;
let commandResultCardEventId =
commandResultEvent?.content.msgtype ===
APP_BOXEL_COMMAND_RESULT_WITH_OUTPUT_MSGTYPE
? commandResultEvent.content.data.cardEventId
: undefined;
let command = commandEvent.content.data.toolCall;
let messageCommand = new MessageCommand(
message,
command.id,
command.name,
command.arguments,
effectiveEventId,
status,
commandResultCardEventId,
owner,
);
return messageCommand;
}

export function formattedMessageForCommand(formattedBody: string) {
return `<p data-test-command-message class="command-message">${formattedBody}</p>`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is just copied from a different position but does anyone know if we have XSS protection or the like for this? Or is it a safe assumption that malicious messages of this event type can’t be produced?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added this 43de05a.

}
20 changes: 16 additions & 4 deletions packages/host/app/lib/matrix-classes/message-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { setOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import { inject as service } from '@ember/service';

import { tracked } from '@glimmer/tracking';

import type CardService from '@cardstack/host/services/card-service';
import type CommandService from '@cardstack/host/services/command-service';
import type MatrixService from '@cardstack/host/services/matrix-service';
Expand All @@ -13,17 +15,27 @@ import { Message } from './message';
type CommandStatus = 'applied' | 'ready' | 'applying';

export default class MessageCommand {
@tracked name: string;
@tracked payload: any;
@tracked commandStatus?: CommandStatus;
@tracked commandResultCardEventId?: string;

constructor(
public message: Message,
public toolCallId: string,
public name: string,
public payload: any, //arguments of toolCall. Its not called arguments due to lint
name: string,
payload: any, //arguments of toolCall. Its not called arguments due to lint
public eventId: string,
private commandStatus: CommandStatus,
public commandResultCardEventId: string | undefined,
commandStatus: CommandStatus,
commandResultCardEventId: string | undefined,
owner: Owner,
) {
setOwner(this, owner);

this.name = name;
this.payload = payload;
this.commandStatus = commandStatus;
this.commandResultCardEventId = commandResultCardEventId;
}

@service declare commandService: CommandService;
Expand Down
9 changes: 7 additions & 2 deletions packages/host/app/lib/matrix-classes/message.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { guidFor } from '@ember/object/internals';
import { tracked } from '@glimmer/tracking';

import { EventStatus } from 'matrix-js-sdk';
Expand Down Expand Up @@ -45,15 +46,15 @@ interface RoomMessageOptional {
export class Message implements RoomMessageInterface {
@tracked formattedMessage: string;
@tracked message: string;
@tracked command?: MessageCommand | null;
@tracked isStreamingFinished?: boolean;

attachedCardIds?: string[] | null;
attachedSkillCardIds?: string[] | null;
index?: number;
transactionId?: string | null;
isStreamingFinished?: boolean;
errorMessage?: string;
clientGeneratedId?: string;
command?: MessageCommand | null;

author: RoomMember;
status: EventStatus | null;
Expand All @@ -62,6 +63,9 @@ export class Message implements RoomMessageInterface {
eventId: string;
roomId: string;

//This property is used for testing purpose
instanceId: string;

constructor(init: RoomMessageInterface) {
Object.assign(this, init);
this.author = init.author;
Expand All @@ -72,6 +76,7 @@ export class Message implements RoomMessageInterface {
this.updated = init.updated;
this.status = init.status;
this.roomId = init.roomId;
this.instanceId = guidFor(this);
}
get isRetryable() {
return (
Expand Down
Loading
Loading