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

Open AI panel when AI app generator starts generating #1989

4 changes: 4 additions & 0 deletions packages/base/command.gts
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,7 @@ export class SendAiAssistantMessageInput extends CardDef {
export class SendAiAssistantMessageResult extends CardDef {
@field eventId = contains(StringField);
}

export class OpenAiAssistantRoomInput extends CardDef {
@field roomId = contains(StringField);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default class CreateBoxelApp extends Command<
this.commandContext,
undefined,
);

let { productRequirements: prdCard, roomId } =
await createPRDCommand.execute(input);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ReloadCardCommand from '@cardstack/boxel-host/commands/reload-card';
import CreateAIAssistantRoomCommand from '@cardstack/boxel-host/commands/create-ai-assistant-room';
import AddSkillsToRoomCommand from '@cardstack/boxel-host/commands/add-skills-to-room';
import SendAiAssistantMessageCommand from '@cardstack/boxel-host/commands/send-ai-assistant-message';
import OpenAiAssistantRoomCommand from '@cardstack/boxel-host/commands/open-ai-assistant-room';

export class CreateProductRequirementsInput extends CardDef {
@field targetAudience = contains(StringField);
Expand Down Expand Up @@ -77,6 +78,14 @@ export default class CreateProductRequirementsInstance extends Command<
let { roomId } = await createRoomCommand.execute({
name: 'Product Requirements Doc Creation',
});

let openAiAssistantRoomCommand = new OpenAiAssistantRoomCommand(
this.commandContext,
);
await openAiAssistantRoomCommand.execute({
roomId,
});

let addSkillsToRoomCommand = new AddSkillsToRoomCommand(
this.commandContext,
);
Expand Down
2 changes: 2 additions & 0 deletions packages/experiments-realm/ai-app-generator.gts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ class DashboardTab extends GlimmerComponent<{
throw new Error('Missing commandContext');
}
let command = new CreateBoxelApp(commandContext, undefined);

this.isGenerating = true;
try {
await command.execute(
Expand Down Expand Up @@ -471,6 +472,7 @@ class RequirementsTab extends GlimmerComponent<{
if (!this.cardRef) {
throw new Error('Can not create a card without a card ref.');
}

await this.args.context?.actions?.createCard?.(
this.cardRef,
this.args.currentRealm,
Expand Down
5 changes: 5 additions & 0 deletions packages/host/app/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { VirtualNetwork } from '@cardstack/runtime-common';

import * as AddSkillsToRoomCommandModule from './add-skills-to-room';
import * as CreateAIAssistantRoomCommandModule from './create-ai-assistant-room';
import * as OpenAiAssistantRoomCommandModule from './open-ai-assistant-room';
import * as PatchCardCommandModule from './patch-card';
import * as ReloadCardCommandModule from './reload-card';
import * as SaveCardCommandModule from './save-card';
Expand Down Expand Up @@ -32,6 +33,10 @@ export function shimHostCommands(virtualNetwork: VirtualNetwork) {
'@cardstack/boxel-host/commands/save-card',
SaveCardCommandModule,
);
virtualNetwork.shimModule(
'@cardstack/boxel-host/commands/open-ai-assistant-room',
OpenAiAssistantRoomCommandModule,
);
virtualNetwork.shimModule(
'@cardstack/boxel-host/commands/send-ai-assistant-message',
SendAiAssistantMessageModule,
Expand Down
29 changes: 29 additions & 0 deletions packages/host/app/commands/open-ai-assistant-room.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { service } from '@ember/service';

import type * as BaseCommandModule from 'https://cardstack.com/base/command';

import HostBaseCommand from '../lib/host-base-command';

import MatrixService from '../services/matrix-service';
import OperatorModeStateService from '../services/operator-mode-state-service';

export default class OpenAiAssistantRoomCommand extends HostBaseCommand<
BaseCommandModule.OpenAiAssistantRoomInput,
undefined
> {
@service private declare operatorModeStateService: OperatorModeStateService;
@service private declare matrixService: MatrixService;

async getInputType() {
let commandModule = await this.loadCommandModule();
const { OpenAiAssistantRoomInput } = commandModule;
return OpenAiAssistantRoomInput;
}

protected async run(
input: BaseCommandModule.OpenAiAssistantRoomInput,
): Promise<undefined> {
this.operatorModeStateService.aiAssistantOpen = true;
this.matrixService.currentRoomId = input.roomId;
}
}
24 changes: 12 additions & 12 deletions packages/host/app/components/ai-assistant/panel.gts
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ export default class AiAssistantPanel extends Component<Signature> {
</div>
{{else if this.isReady}}
{{! below if statement is covered in 'isReady' check above but added due to glint not realizing it }}
{{#if this.currentRoomId}}
{{#if this.matrixService.currentRoomId}}
<Room
@roomId={{this.currentRoomId}}
@roomId={{this.matrixService.currentRoomId}}
@monacoSDK={{this.monacoSDK}}
/>
{{/if}}
Expand Down Expand Up @@ -362,7 +362,6 @@ export default class AiAssistantPanel extends Component<Signature> {
@service private declare router: RouterService;
@service private declare commandService: CommandService;

@tracked private currentRoomId: string | undefined;
@tracked private isShowingPastSessions = false;
@tracked private roomToRename: SessionRoomData | undefined = undefined;
@tracked private roomToDelete: SessionRoomData | undefined = undefined;
Expand Down Expand Up @@ -403,14 +402,14 @@ export default class AiAssistantPanel extends Component<Signature> {
]);
}
if (roomToEnter) {
this.currentRoomId = roomToEnter.roomId;
this.matrixService.currentRoomId = roomToEnter.roomId;
return;
}
}

let latestRoom = this.latestRoom;
if (latestRoom) {
this.currentRoomId = latestRoom.roomId;
this.matrixService.currentRoomId = latestRoom.roomId;
return;
}

Expand All @@ -423,8 +422,8 @@ export default class AiAssistantPanel extends Component<Signature> {
}

private get roomResource() {
return this.currentRoomId
? this.roomResources.get(this.currentRoomId)
return this.matrixService.currentRoomId
? this.roomResources.get(this.matrixService.currentRoomId)
: undefined;
}

Expand Down Expand Up @@ -464,7 +463,7 @@ export default class AiAssistantPanel extends Component<Signature> {
} catch (e) {
console.log(e);
this.displayRoomError = true;
this.currentRoomId = undefined;
this.matrixService.currentRoomId = undefined;
}
});

Expand Down Expand Up @@ -538,11 +537,10 @@ export default class AiAssistantPanel extends Component<Signature> {

@action
private enterRoom(roomId: string, hidePastSessionsList = true) {
this.currentRoomId = roomId;
this.matrixService.currentRoomId = roomId;
if (hidePastSessionsList) {
this.hidePastSessions();
}
window.localStorage.setItem(CurrentRoomIdPersistenceKey, roomId);
}

@action private setRoomToRename(room: SessionRoomData) {
Expand Down Expand Up @@ -591,7 +589,7 @@ export default class AiAssistantPanel extends Component<Signature> {
window.localStorage.removeItem(NewSessionIdPersistenceKey);
}

if (this.currentRoomId === roomId) {
if (this.matrixService.currentRoomId === roomId) {
window.localStorage.removeItem(CurrentRoomIdPersistenceKey);
if (this.latestRoom) {
this.enterRoom(this.latestRoom.roomId, false);
Expand Down Expand Up @@ -624,7 +622,9 @@ export default class AiAssistantPanel extends Component<Signature> {

private get isReady() {
return Boolean(
this.currentRoomId && this.maybeMonacoSDK && this.doCreateRoom.isIdle,
this.matrixService.currentRoomId &&
this.maybeMonacoSDK &&
this.doCreateRoom.isIdle,
);
}
}
28 changes: 9 additions & 19 deletions packages/host/app/components/operator-mode/submode-layout.gts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import AiAssistantPanel from '@cardstack/host/components/ai-assistant/panel';
import AiAssistantToast from '@cardstack/host/components/ai-assistant/toast';
import ProfileSettingsModal from '@cardstack/host/components/operator-mode/profile/profile-settings-modal';
import ProfileInfoPopover from '@cardstack/host/components/operator-mode/profile-info-popover';
import ENV from '@cardstack/host/config/environment';

import type IndexController from '@cardstack/host/controllers';

import { assertNever } from '@cardstack/host/utils/assert-never';
Expand All @@ -44,8 +44,6 @@ import WorkspaceChooser from './workspace-chooser';
import type MatrixService from '../../services/matrix-service';
import type OperatorModeStateService from '../../services/operator-mode-state-service';

const { APP } = ENV;

interface Signature {
Element: HTMLDivElement;
Args: {
Expand Down Expand Up @@ -85,7 +83,6 @@ type PanelWidths = {
};

export default class SubmodeLayout extends Component<Signature> {
@tracked private isAiAssistantVisible = false;
@tracked private searchSheetMode: SearchSheetMode = SearchSheetModes.Closed;
@tracked private profileSettingsOpened = false;
@tracked private profileSummaryOpened = false;
Expand Down Expand Up @@ -117,7 +114,7 @@ export default class SubmodeLayout extends Component<Signature> {
}

private get aiAssistantVisibilityClass() {
return this.isAiAssistantVisible
return this.operatorModeStateService.aiAssistantOpen
? 'ai-assistant-open'
: 'ai-assistant-closed';
}
Expand Down Expand Up @@ -161,11 +158,6 @@ export default class SubmodeLayout extends Component<Signature> {
this.operatorModeStateService.updateSubmode(submode);
}

@action
private toggleChat() {
this.isAiAssistantVisible = !this.isAiAssistantVisible;
}

@action private closeSearchSheet() {
if (this.suppressSearchClose) {
return;
Expand Down Expand Up @@ -317,23 +309,21 @@ export default class SubmodeLayout extends Component<Signature> {
@onCardSelect={{this.handleCardSelectFromSearch}}
@onInputInsertion={{this.storeSearchElement}}
/>
{{#if (and APP.experimentalAIEnabled (not @hideAiAssistant))}}
{{#if (not @hideAiAssistant)}}
<AiAssistantToast
@hide={{this.isAiAssistantVisible}}
@onViewInChatClick={{this.toggleChat}}
@hide={{this.operatorModeStateService.aiAssistantOpen}}
@onViewInChatClick={{this.operatorModeStateService.toggleAiAssistant}}
/>
<AiAssistantButton
class='chat-btn'
@isActive={{this.isAiAssistantVisible}}
{{on 'click' this.toggleChat}}
@isActive={{this.operatorModeStateService.aiAssistantOpen}}
{{on 'click' this.operatorModeStateService.toggleAiAssistant}}
/>
{{/if}}
</ResizablePanel>
{{#if
(and
APP.experimentalAIEnabled
(not @hideAiAssistant)
this.isAiAssistantVisible
(not @hideAiAssistant) this.operatorModeStateService.aiAssistantOpen
)
}}
<ResizablePanel
Expand All @@ -342,7 +332,7 @@ export default class SubmodeLayout extends Component<Signature> {
@collapsible={{false}}
>
<AiAssistantPanel
@onClose={{this.toggleChat}}
@onClose={{this.operatorModeStateService.toggleAiAssistant}}
@resizeHandle={{ResizeHandle}}
class='ai-assistant-panel
{{if this.workspaceChooserOpened "left-border"}}'
Expand Down
2 changes: 1 addition & 1 deletion packages/host/app/config/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ declare const config: {
APP: Record<string, unknown>;
matrixURL: string;
matrixServerName: string;
experimentalAIEnabled: boolean;

resolvedBaseRealmURL: string;
hostsOwnAssets: boolean;
realmsServed?: string[];
Expand Down
14 changes: 14 additions & 0 deletions packages/host/app/services/matrix-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export default class MatrixService extends Service {
@tracked private _isInitializingNewUser = false;
@tracked private _isNewUser = false;
@tracked private postLoginCompleted = false;
@tracked private _currentRoomId: string | undefined;

profile = getMatrixProfile(this, () => this.userId);

Expand Down Expand Up @@ -148,6 +149,19 @@ export default class MatrixService extends Service {
this.currentUserEventReadReceipts.set(eventId, receipt);
}

get currentRoomId(): string | undefined {
return this._currentRoomId;
}

set currentRoomId(value: string | undefined) {
this._currentRoomId = value;
if (value) {
window.localStorage.setItem(CurrentRoomIdPersistenceKey, value);
} else {
window.localStorage.removeItem(CurrentRoomIdPersistenceKey);
}
}

get ready() {
return this.#ready;
}
Expand Down
13 changes: 13 additions & 0 deletions packages/host/app/services/operator-mode-state-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export default class OperatorModeStateService extends Service {
codePath: null,
openDirs: new TrackedMap<string, string[]>(),
});
@tracked private _aiAssistantOpen = false;
private cachedRealmURL: URL | null = null;
private openFileSubscribers: OpenFileSubscriber[] = [];

Expand All @@ -99,6 +100,18 @@ export default class OperatorModeStateService extends Service {
this.reset.register(this);
}

get aiAssistantOpen() {
return this._aiAssistantOpen;
}

set aiAssistantOpen(value: boolean) {
this._aiAssistantOpen = value;
}

toggleAiAssistant = () => {
this.aiAssistantOpen = !this.aiAssistantOpen;
};

resetState() {
this.state = new TrackedObject({
stacks: new TrackedArray([]),
Expand Down
4 changes: 0 additions & 4 deletions packages/host/config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ module.exports = function (environment) {
APP: {
// Here you can pass flags/options to your application instance
// when it is created
experimentalAIEnabled:
process.env.EXPERIMENTAL_AI_ENABLED === 'true' ? true : false,
},
'ember-cli-mirage': {
enabled: false,
Expand Down Expand Up @@ -52,7 +50,6 @@ module.exports = function (environment) {
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true;
ENV.APP.experimentalAIEnabled = true;
}

if (environment === 'test') {
Expand All @@ -65,7 +62,6 @@ module.exports = function (environment) {

ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
ENV.APP.experimentalAIEnabled = true;
ENV.autoSaveDelayMs = 0;
ENV.monacoDebounceMs = 0;
ENV.monacoCursorDebounceMs = 0;
Expand Down
Loading
Loading