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

Epic: Jovu Phase 2 #8341

Merged
merged 48 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
492bfb4
fix(client):update text
yuval-hazaz Apr 24, 2024
ea730ee
style(client):temp jovu logo
yuval-hazaz Apr 28, 2024
ad57245
feat(server): add plugin catalog data for Jovu
yuval-hazaz Apr 28, 2024
9e1fa87
feat(server):install plugin from jovu
yuval-hazaz Apr 28, 2024
5b10155
feat(server): create multiple plugins
yuval-hazaz Apr 28, 2024
51cfe22
feat(server):add module functions for assistant service
yuval-hazaz Apr 28, 2024
846ed70
feat(server):Jovu create dto
yuval-hazaz Apr 29, 2024
611aff7
feat(client):decrease the size of description field
yuval-hazaz Apr 29, 2024
7abdd11
feat(client):improve dto UX
yuval-hazaz Apr 29, 2024
efb1e4a
fix(server):initialize properties
yuval-hazaz Apr 29, 2024
5fb3c0b
feat(client):auto select module navigation item
yuval-hazaz Apr 29, 2024
d836cc1
fix(client):remove unused imports
yuval-hazaz Apr 29, 2024
d562be5
fix(server): fix flow
yuval-hazaz Apr 29, 2024
82e68d6
Merge branch 'next' into feat/jovu-plugins
yuval-hazaz Apr 29, 2024
4bc0516
Merge branch 'feat/jovu-plugins' into feat/jovu-api
yuval-hazaz Apr 29, 2024
71b16b1
fix(client):expand navigation item on URL change
yuval-hazaz Apr 29, 2024
9f2b7ec
fix(server):plugins url
yuval-hazaz Apr 29, 2024
43c5ff9
Merge branch 'feat/jovu-plugins' of https://github.com/amplication/am…
yuval-hazaz Apr 29, 2024
dae8f5f
Merge branch 'feat/jovu-plugins' into feat/jovu-api
yuval-hazaz Apr 29, 2024
eedd314
Merge branch 'feat/jovu-api' into style/dto-properties-ux
yuval-hazaz Apr 29, 2024
7b1e37f
style(client):remove left padding
yuval-hazaz Apr 29, 2024
f625f58
Merge branch 'style/dto-properties-ux' of https://github.com/amplicat…
yuval-hazaz Apr 29, 2024
4ba7858
feast(server):jovu create enum
yuval-hazaz Apr 29, 2024
54f14b4
feat(server):add support to get a list of actions in the assistant
yuval-hazaz Apr 29, 2024
b21c97c
feat(server):create action with jovu
yuval-hazaz Apr 29, 2024
0fb6591
feat(server):force jovu limitations
yuval-hazaz Apr 30, 2024
8900de2
feat(client):force jovu limitations
yuval-hazaz Apr 30, 2024
8ccf278
test(server):fix test
yuval-hazaz May 1, 2024
e5a32e0
Merge branch 'feat/jovu-create-enum' into feat/jovu-get-actions
yuval-hazaz May 1, 2024
83bc41b
Merge branch 'feat/jovu-get-actions' into feat/jovu-create-action
yuval-hazaz May 1, 2024
d0bba09
Merge branch 'feat/jovu-create-action' into feat/jovu-usage-limits
yuval-hazaz May 1, 2024
eccde6d
feat(client):update contact us URL
yuval-hazaz May 1, 2024
dda7577
Merge branch 'feat/jovu-usage-limits' of https://github.com/amplicati…
yuval-hazaz May 1, 2024
49f472c
Merge pull request #8350 from amplication/feat/jovu-create-action
yuval-hazaz May 1, 2024
882dc1e
Merge pull request #8348 from amplication/feat/jovu-get-actions
yuval-hazaz May 1, 2024
825d6cb
Merge pull request #8343 from amplication/style/dto-properties-ux
yuval-hazaz May 1, 2024
1e6d764
Merge pull request #8346 from amplication/feat/jovu-create-enum
yuval-hazaz May 1, 2024
fe5e734
Merge pull request #8342 from amplication/feat/jovu-api
yuval-hazaz May 1, 2024
041bd60
Merge branch 'next' into feat/jovu-plugins
yuval-hazaz May 1, 2024
dca1a30
chore(server):remove unused code
yuval-hazaz May 1, 2024
b90216d
test(server):create test for assistant service
yuval-hazaz May 1, 2024
4336414
test(server):add test
yuval-hazaz May 1, 2024
3ea8571
test(server):test function execution
yuval-hazaz May 1, 2024
281157a
test(server):test function execution
yuval-hazaz May 1, 2024
9484883
Merge pull request #8358 from amplication/feat/jovu-usage-limits
yuval-hazaz May 1, 2024
f52db31
test(server):use beforeAll
yuval-hazaz May 2, 2024
63ad873
Merge pull request #8365 from amplication/test/assistant-service
yuval-hazaz May 2, 2024
f4c739d
Merge branch 'next' into feat/jovu-plugins
yuval-hazaz May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"Formik",
"IBLOCK",
"isequalwith",
"jovu",
"kafkajs",
"linkcode",
"logform",
Expand Down
7 changes: 7 additions & 0 deletions packages/amplication-client/src/Assistant/Assistant.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ $assistant-width: 350px;
$assistant-handle-width: 24px;
$assistant-handle-top: 150px;
$assistant-handle-margin: 40px;
$avatar-size: 30px;

#root {
// --assistant-background: var(--theme-gradient);
Expand Down Expand Up @@ -199,5 +200,11 @@ $assistant-handle-margin: 40px;
justify-content: flex-start;
font-weight: semi-bold;
color: var(--assistant-role-color);

.user-avatar__initials {
width: $avatar-size;
height: $avatar-size;
font-size: var(--h3-font-size);
}
}
}
9 changes: 8 additions & 1 deletion packages/amplication-client/src/Assistant/Assistant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import AssistantMessage from "./AssistantMessage";
import classNames from "classnames";
import { useAppContext } from "../context/appContext";
import { Link } from "react-router-dom";
import jovu from "../assets/jovu.svg";
type SendMessageType = models.SendAssistantMessageInput;

const INITIAL_VALUES: SendMessageType = {
Expand Down Expand Up @@ -100,7 +101,13 @@ const Assistant = () => {
)}
>
<div className={`${CLASS_NAME}__header`}>
<Icon icon="ai" color={EnumTextColor.White} size="large" />
<img
src={jovu}
alt="jovu"
width={30}
height={30}
style={{ background: "white", borderRadius: "50%" }}
/>
<Text className={`${CLASS_NAME}__title`} textStyle={EnumTextStyle.H4}>
Jovu (Beta)
</Text>
Expand Down
11 changes: 10 additions & 1 deletion packages/amplication-client/src/Assistant/AssistantMessage.tsx
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
Button,
EnumButtonStyle,
EnumTextColor,

Check warning on line 4 in packages/amplication-client/src/Assistant/AssistantMessage.tsx

View workflow job for this annotation

GitHub Actions / Continuous Integration

'EnumTextColor' is defined but never used
Icon,

Check warning on line 5 in packages/amplication-client/src/Assistant/AssistantMessage.tsx

View workflow job for this annotation

GitHub Actions / Continuous Integration

'Icon' is defined but never used
} from "@amplication/ui/design-system";
import ReactMarkdown from "react-markdown";
import UserBadge from "../Components/UserBadge";
Expand All @@ -10,6 +10,8 @@
import { AssistantMessageWithOptions } from "./hooks/useAssistant";
import { Link } from "react-router-dom";

import jovu from "../assets/jovu.svg";

const CLASS_NAME = "assistant";

type Props = {
Expand All @@ -28,7 +30,14 @@
</>
) : (
<>
<Icon icon="ai" color={EnumTextColor.ThemeTurquoise} size="large" />
<img
src={jovu}
alt="jovu"
width={30}
height={30}
style={{ background: "white", borderRadius: "50%" }}
/>
{/* <Icon icon="ai" color={EnumTextColor.ThemeTurquoise} size="large" /> */}
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
Jovu
</>
)}
Expand Down
10 changes: 6 additions & 4 deletions packages/amplication-client/src/Workspaces/WorkspaceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,16 @@ function WorkspaceForm() {
gap={EnumGapSize.Small}
>
<div>
Turn on this option to enable advanced features using
artificial intelligence. These include personalized
Manage Amplication AI-powered features and
enable/disable advanced features using artificial
intelligence. These include personalized
recommendations, and automation of tasks.
</div>
<div>
Note: This may involve processing your data with AI
technologies. When disabled, we will never share your
data with any AI or large language model services.
technologies while keeping your data secure. When
disabled, we will never share your data with any AI or
large language model services.
</div>
</FlexItem>
</Text>
Expand Down
3 changes: 3 additions & 0 deletions packages/amplication-client/src/assets/jovu.svg
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/amplication-server/.env
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ CHAT_OPENAI_KEY="CHAT_OPENAI_KEY"
CHAT_ASSISTANT_ID="CHAT_ASSISTANT_ID"
FEATURE_AI_ASSISTANT_ENABLED=true

PLUGIN_API_URL="https://plugin-api.amplication.com/graphql"
mulygottlieb marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ResourceModule } from "../resource/resource.module";
import { ModuleModule } from "../module/module.module";
import { ProjectModule } from "../project/project.module";
import { GraphqlSubscriptionPubSubKafkaService } from "./graphqlSubscriptionPubSubKafka.service";
import { PluginCatalogModule } from "../pluginCatalog/pluginCatalog.module";
import { PluginInstallationModule } from "../pluginInstallation/pluginInstallation.module";

@Module({
imports: [
Expand All @@ -15,6 +17,8 @@ import { GraphqlSubscriptionPubSubKafkaService } from "./graphqlSubscriptionPubS
ResourceModule,
ModuleModule,
ProjectModule,
PluginCatalogModule,
PluginInstallationModule,
],
providers: [
AssistantService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import { AssistantStream } from "openai/lib/AssistantStream";
import { AssistantMessageDelta } from "./dto/AssistantMessageDelta";
import { AmplicationError } from "../../errors/AmplicationError";
import { GraphqlSubscriptionPubSubKafkaService } from "./graphqlSubscriptionPubSubKafka.service";
import { PluginCatalogService } from "../pluginCatalog/pluginCatalog.service";
import { omit } from "lodash";
import { PluginInstallationService } from "../pluginInstallation/pluginInstallation.service";

enum EnumAssistantFunctions {
CreateEntity = "createEntity",
Expand All @@ -30,10 +33,14 @@ enum EnumAssistantFunctions {
CreateProject = "createProject",
CommitProjectPendingChanges = "commitProjectPendingChanges",
GetProjectPendingChanges = "getProjectPendingChanges",
GetPlugins = "getPlugins",
InstallPlugins = "installPlugins",
}

const MESSAGE_UPDATED_EVENT = "assistantMessageUpdated";

export const PLUGIN_LATEST_VERSION_TAG = "latest";

type MessageLoggerContext = {
messageContext: {
workspaceId: string;
Expand Down Expand Up @@ -62,6 +69,8 @@ export class AssistantService {
private readonly moduleService: ModuleService,
private readonly projectService: ProjectService,
private readonly graphqlSubscriptionKafkaService: GraphqlSubscriptionPubSubKafkaService,
private readonly pluginCatalogService: PluginCatalogService,
private readonly pluginInstallationService: PluginInstallationService,

configService: ConfigService
) {
Expand Down Expand Up @@ -94,7 +103,7 @@ export class AssistantService {
snapshot: string,
completed: boolean
) => {
this.logger.info("Chat: Message updated");
//this.logger.debug("Chat: Message updated");
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
const message: AssistantMessageDelta = {
id: "messageId",
threadId,
Expand Down Expand Up @@ -665,5 +674,58 @@ export class AssistantService {
: "Entity",
}));
},
getPlugins: async (args: undefined, context: AssistantContext) => {
const plugins = (await this.pluginCatalogService.getPlugins()).map(
(plugin) => omit(plugin, ["__typename"])
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
);
this.logger.debug(
`Chat: Plugins: ${JSON.stringify(plugins)}`,
null,
context
);
return plugins;
},
installPlugins: async (
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
args: { pluginIds: string[]; serviceId: string },
context: AssistantContext
) => {
//iterate over the pluginIds and install each plugin synchronously
//to support synchronous installation of multiple plugins we need first to fix the plugins order code in the pluginInstallation Service
const installations = [];
for (const pluginId of args.pluginIds) {
const plugin =
await this.pluginCatalogService.getPluginWithLatestVersion(pluginId);
const pluginVersion = plugin.versions[0];

const { version, settings, configurations } = pluginVersion;

const installation = await this.pluginInstallationService.create(
{
data: {
displayName: plugin.name,
pluginId: pluginId,
enabled: true,
npm: plugin.npm,
version: version,
settings: settings,
configurations: configurations,
resource: { connect: { id: args.serviceId } },
},
},
context.user
);

installations.push({
result: installation,
link: `${this.clientHost}/${context.workspaceId}/${context.projectId}/${args.serviceId}/plugins/installed/${installation.id}`,
});
}

return {
installations,
pluginsCatalogLink: `${this.clientHost}/${context.workspaceId}/${context.projectId}/plugins/catalog`,
allInstalledPluginsLink: `${this.clientHost}/${context.workspaceId}/${context.projectId}/plugins/installed`,
};
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { PluginCatalogItemVersion } from "./PluginCatalogItemVersion";

export class PluginCatalogItem {
id: string;
pluginId: string;
name: string;
description: string;
repo: string;
npm: string;
icon: string;
github: string;
website: string;
categories: string[];
type: string;
taggedVersions: { [tag: string]: string };
versions: PluginCatalogItemVersion[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { JsonValue } from "type-fest";

export class PluginCatalogItemVersion {
version: string;
isLatest: boolean;
settings: JsonValue;
configurations: JsonValue;
id: string;
pluginId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from "@nestjs/common";
import { PluginCatalogService } from "./pluginCatalog.service";

@Module({
imports: [],
providers: [PluginCatalogService],
exports: [PluginCatalogService],
})
export class PluginCatalogModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Injectable } from "@nestjs/common";
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
import { ConfigService } from "@nestjs/config";
import { Env } from "../../env";
import { PluginCatalogItem } from "./dto/PluginCatalogItem";

@Injectable()
export class PluginCatalogService {
private client: ApolloClient<any>;

constructor(configService: ConfigService) {
this.client = new ApolloClient({
uri: configService.get<string>(Env.PLUGIN_API_URL),
cache: new InMemoryCache(),
});
}

async getPluginWithLatestVersion(
pluginId: string
): Promise<PluginCatalogItem> {
const query = gql`
query GetPlugin($where: PluginWhereInput) {
plugins(where: $where) {
pluginId
name
icon
description
taggedVersions
npm
github
categories
versions(
where: { deprecated: { equals: null } }
orderBy: { createdAt: Desc }
) {
id
pluginId
deprecated
isLatest
version
settings
configurations
}
}
}
`;

try {
const { data } = await this.client.query<{
plugins: PluginCatalogItem[];
}>({
query,
variables: {
where: {
categories: {}, //this is required to workaround an issue in the API
pluginId: {
equals: pluginId,
},
},
},
});
const plugin =
data.plugins && data.plugins.length ? data.plugins[0] : undefined;
if (plugin) {
const versions = plugin.versions.filter((version) => version.isLatest);
return {
...plugin,
versions,
};
}
return undefined;
yuval-hazaz marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
throw new Error(`Failed to fetch plugin with ID ${pluginId}: ${error}`);
}
}

async getPlugins(): Promise<PluginCatalogItem[]> {
const query = gql`
query GetPlugins {
plugins {
pluginId
name
icon
description
npm
github
categories
}
}
`;

try {
const { data } = await this.client.query<{
plugins: PluginCatalogItem[];
}>({
query,
});
return data.plugins;
} catch (error) {
throw new Error(`Failed to fetch plugins: ${error}`);
}
}
}
1 change: 1 addition & 0 deletions packages/amplication-server/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export class Env {
static readonly CHAT_OPENAI_KEY = "CHAT_OPENAI_KEY";
static readonly CHAT_ASSISTANT_ID = "CHAT_ASSISTANT_ID";
static readonly FEATURE_AI_ASSISTANT_ENABLED = "FEATURE_AI_ASSISTANT_ENABLED";
static readonly PLUGIN_API_URL = "PLUGIN_API_URL";
}