Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion plugins/genai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Add this to your Backstage configuration file (for example `app-config.yaml`):
genai:
agents:
general: # This matches the URL in the frontend
description: General chat assistant
tagLine: General chat assistant
prompt: >
You are an expert in platform engineering and answer questions in a succinct and easy to understand manner.

Expand Down Expand Up @@ -203,6 +203,22 @@ genai:

The tool for invoking agents simply accepts a parameter called `query` which is expected to be a natural language query, and it will respond with the raw text output of the agent.

## UI Customization

To customize agent titles, descriptions, and welcome messages in the chat interface, you need to add `title`, `description`, and `welcomeMessage` to your agent config in `app-config.yaml`

```yaml
genai:
agents:
general:
title: '🤖 AI Assistant'
description: 'Your intelligent platform companion'
welcomeMessage: 'Hello! Check out our [docs](/docs) for more info!'
# ... other agent config
```

The welcome message supports Markdown formatting. For details, see the [UI Customization Guide](./docs/ui-customization.md) and [Backstage config visibility documentation](https://backstage.io/docs/conf/defining/#visibility).

## Further reading

You can view the rest of the documentation to understand how to evolve your chat assistant
Expand Down
23 changes: 23 additions & 0 deletions plugins/genai/frontend/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,28 @@ export interface Config {
*/
showInformation?: boolean;
};

agents?: {
[agentName: string]: {
/**
* Title displayed in the UI header
* @visibility frontend
*/
title?: string;

/**
* Descriptive tag line for the agent, displayed in the UI header
* If not set, the "'Start chatting!'" message will be used
* @visibility frontend
*/
tagLine?: string;

/**
* Welcome message shown when no conversation has started
* @visibility frontend
*/
welcomeMessage?: string;
};
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ChatInputComponent } from '../ChatInputComponent';
import { useParams } from 'react-router-dom';
import { LinearProgress, makeStyles } from '@material-ui/core';
import { useChatSession } from '../../hooks';
import { useAgentMetadata } from '../../hooks/useAgentMetadata';

const useStyles = makeStyles({
flex: {
Expand Down Expand Up @@ -54,6 +55,9 @@ export const AgentPage = ({ title = 'Chat Assistant' }: { title?: string }) => {
throw new Error('agent name is not defined');
}

const agentMetadata = useAgentMetadata(agentName);
const agentTitle = agentMetadata.title || title;

const { messages, isInitializing, isLoading, onUserMessage, onClear } =
useChatSession({
agentName,
Expand All @@ -69,14 +73,15 @@ export const AgentPage = ({ title = 'Chat Assistant' }: { title?: string }) => {

return (
<Page themeId="tool">
<Header title={title} />
<Header title={agentTitle} />
<Content noPadding>
<div className={classes.flex}>
<ChatHistoryComponent
messages={messages}
className={classes.grow}
isStreaming={isLoading}
showInformation={showInformation}
agentMetadata={agentMetadata}
/>
<div className={classes.chatInputContainer}>
<InfoCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Info from '@material-ui/icons/Info';
import Error from '@material-ui/icons/Error';
import { ToolsModal } from './ToolsModal';
import { makeStyles } from '@material-ui/core';
import { AgentUIConfig } from '../../hooks';

const useStyles = makeStyles(theme => ({
container: {
Expand Down Expand Up @@ -128,6 +129,7 @@ export interface ChatHistoryComponentProps {
isStreaming?: boolean;
className?: string;
showInformation: boolean;
agentMetadata: AgentUIConfig;
}

function getMessageExtraClass(message: ChatMessage, classes: any): string {
Expand Down Expand Up @@ -158,6 +160,7 @@ export const ChatHistoryComponent = ({
messages,
className,
showInformation,
agentMetadata,
}: ChatHistoryComponentProps) => {
const classes = useStyles();

Expand Down Expand Up @@ -187,9 +190,16 @@ export const ChatHistoryComponent = ({
<div className={classes.markdown} ref={contentRef}>
{messages!.length === 0 && (
<EmptyState
missing="data"
title="Start chatting!"
description="This assistant can answer questions for you, type a message below to get started."
missing="content"
title={agentMetadata.tagLine || 'Start chatting!'}
description={
<MarkdownContent
content={
agentMetadata.welcomeMessage ||
'This assistant can answer questions for you, type a message below to get started.'
}
/>
}
/>
)}

Expand Down
4 changes: 4 additions & 0 deletions plugins/genai/frontend/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
*/

export * from './useChatSession';
export {
useAgentMetadata,
type AgentMetadata as AgentUIConfig,
} from './useAgentMetadata';
46 changes: 46 additions & 0 deletions plugins/genai/frontend/src/hooks/useAgentMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { useApi, configApiRef } from '@backstage/core-plugin-api';

export interface AgentMetadata {
title: string;
tagLine: string;
welcomeMessage: string;
}

/**
* Hook to load agent metadata from app-config.yaml with fallback defaults
*/
export const useAgentMetadata = (agentName: string): AgentMetadata => {
const config = useApi(configApiRef);

// Load agent config directly (no metadata wrapper)
const agentConfig = config.getOptionalConfig(`genai.agents.${agentName}`);

if (!agentConfig) {
throw new Error(`Agent ${agentName} not found`);
}

const title = agentConfig.getOptionalString('title') ?? 'Chat Assistant';
const tagLine = agentConfig.getOptionalString('tagLine') ?? 'Start chatting!';
const welcomeMessage =
agentConfig.getOptionalString('welcomeMessage') ??
'This assistant can answer questions for you, type a message below to get started.';

return {
title,
tagLine: tagLine,
welcomeMessage,
};
};