Skip to content

Commit e6ae868

Browse files
authored
feat(ui): align prompt examples with a2a (#992)
Signed-off-by: Petr Kadlec <petr@puradesign.cz>
1 parent f090283 commit e6ae868

File tree

9 files changed

+65
-34
lines changed

9 files changed

+65
-34
lines changed

agents/ui/hello/src/extensions.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class AgentDetailContributor(BaseModel):
1616
class BeeAIUI(AgentExtension):
1717
def __init__(self, ui_type: str, user_greeting: str, tools: list[BeeAIUITool], framework: str, license: str, programming_language: str,
1818
source_code_url: str, container_image_url: str | None = None, author: AgentDetailContributor | None = None,
19-
contributors: list[AgentDetailContributor] | None = None, starter_prompts: list[str] |None = None ):
19+
contributors: list[AgentDetailContributor] | None = None):
2020
super().__init__(
21-
uri="beeai_ui",
21+
uri="https://a2a-extensions.beeai.dev/ui/agent-detail/v1",
2222
params={
2323
"ui_type": ui_type,
2424
"user_greeting": user_greeting,
@@ -29,7 +29,5 @@ def __init__(self, ui_type: str, user_greeting: str, tools: list[BeeAIUITool], f
2929
"source_code_url": source_code_url,
3030
"container_image_url": container_image_url,
3131
"author": author,
32-
"contributors": contributors,
33-
"starter_prompts": starter_prompts,
34-
}
32+
"contributors": contributors, }
3533
)

agents/ui/hello/src/main.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
from sdk import Server
55
from extensions import BeeAIUITool, AgentDetailContributor, BeeAIUI
66
from models import CitationMetadata, TextPart, TrajectoryMetadata
7-
from fastapi.middleware.cors import CORSMiddleware
7+
from a2a.types import (
8+
AgentSkill,
9+
TextPart,
10+
)
811

912
server = Server()
1013

@@ -39,8 +42,23 @@
3942
AgentDetailContributor(name= 'Petr Kadlec', email="petr.kadlec@ibm.com"),
4043
AgentDetailContributor(name= 'Petr Bulánek', email="petr.bulanek@ibm.com"),
4144
],
42-
starter_prompts=['Write a research report about Generative AI','Should I buy Apple stock now?','Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolor. This is what a long query would look like, 2 lines maximum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolor. This is what a long query would look like, 2 lines maximum...','What is the meaning of life?','Tell me a joke','What is the capital of France?','How do I make a cake?']
4345
),
46+
skills=[
47+
AgentSkill(
48+
id="echo",
49+
name="Echo",
50+
description="This is echo skill",
51+
tags=["echo"],
52+
examples=['Should I buy Apple stock now?','Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolor. This is what a long query would look like, 2 lines maximum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolor. This is what a long query would look like, 2 lines maximum...','What is the meaning of life?','Tell me a joke','What is the capital of France?','How do I make a cake?']
53+
),
54+
AgentSkill(
55+
id="echo2",
56+
name="Echo 2",
57+
description="This is echo 2 skill",
58+
tags=["echo"],
59+
examples=['What is the meaning of life?','Tell me a joke','What is the capital of France?','How do I make a cake?']
60+
)
61+
],
4462
)
4563
async def hello_world(input: list[TextPart]):
4664
yield TextPart(content="Hello World")

agents/ui/hello/src/sdk.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
AgentCard,
1212
AgentCapabilities,
1313
TaskState,
14+
AgentSkill,
1415
Role,
1516
Part,
1617
TextPart as A2ATextPart,
@@ -42,6 +43,7 @@ def agent_decorator(
4243
input_content_types: list[str] | None = None,
4344
output_content_types: list[str] | None = None,
4445
ui: BeeAIUI | None = None,
46+
skills: list[AgentSkill] = [],
4547
) -> Callable[[Callable], RunnableAgent]:
4648
def decorator(fn: Callable) -> RunnableAgent:
4749
class DecoratedAgent(RunnableAgent):
@@ -62,7 +64,7 @@ def run(self, input: list[str]) -> AsyncGenerator[str, str]:
6264
streaming=True,
6365
extensions=extensions,
6466
),
65-
skills=[],
67+
skills=skills,
6668
tags=[],
6769
examples=[],
6870
)
@@ -123,6 +125,7 @@ def agent(
123125
input_content_types: list[str] | None = None,
124126
output_content_types: list[str] | None = None,
125127
ui: BeeAIUI | None = None,
128+
skills: list[AgentSkill] = []
126129
) -> Callable:
127130
def decorator(fn: Callable) -> Callable:
128131
runnable_agent = agent_decorator(
@@ -131,6 +134,7 @@ def decorator(fn: Callable) -> Callable:
131134
input_content_types=input_content_types,
132135
output_content_types=output_content_types,
133136
ui=ui,
137+
skills=skills
134138
)(fn)
135139
self.agent_card = runnable_agent
136140
self.agent = DefaultAgentExecutor(runnable_agent)

apps/beeai-ui/src/modules/agents/api/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export interface UIExtensionParams {
3939
container_image_url?: string;
4040
author?: AgentContributor;
4141
contributors?: AgentContributor[];
42-
starter_prompts?: string[];
4342
}
4443

4544
/**

apps/beeai-ui/src/modules/agents/utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,10 @@ export function getAgentTags(agent: Agent) {
5353
(a, b) => a.toLocaleLowerCase() === b.toLocaleLowerCase(),
5454
);
5555
}
56+
57+
export function getAgentPromptExamples(agent: Agent) {
58+
return uniqWith(
59+
agent.skills.flatMap(({ examples }) => examples).filter(isNotNull),
60+
(a, b) => a.toLocaleLowerCase() === b.toLocaleLowerCase(),
61+
);
62+
}

apps/beeai-ui/src/modules/runs/components/PromptSuggestions.module.scss renamed to apps/beeai-ui/src/modules/runs/components/PromptExamples.module.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
.root {
1313
z-index: z('modal') - 1;
14-
padding: 0 !important;
14+
15+
// use grid-margin to align with run input
16+
padding-inline: var(--cds-grid-margin) !important;
17+
margin-inline-start: calc(-1 * var(--cds-grid-margin));
1518
}
1619

1720
.content {

apps/beeai-ui/src/modules/runs/components/PromptSuggestions.tsx renamed to apps/beeai-ui/src/modules/runs/components/PromptExamples.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ import { Container } from '#components/layouts/Container.tsx';
2323
import { Tooltip } from '#components/Tooltip/Tooltip.tsx';
2424
import { fadeProps } from '#utils/fadeProps.ts';
2525

26-
import classes from './PromptSuggestions.module.scss';
26+
import classes from './PromptExamples.module.scss';
2727

2828
interface Props {
2929
inputRef: RefObject<HTMLTextAreaElement | null>;
3030
isOpen: boolean;
31-
suggestions: string[];
31+
examples: string[];
3232
setIsOpen: Dispatch<SetStateAction<boolean>>;
3333
onSubmit: (input: string) => void;
3434
}
3535

36-
export function PromptSuggestions({ inputRef, isOpen, suggestions, setIsOpen, onSubmit }: Props) {
36+
export function PromptExamples({ inputRef, isOpen, examples, setIsOpen, onSubmit }: Props) {
3737
const { refs, floatingStyles, context, placement } = useFloating({
3838
placement: 'bottom-start',
3939
open: isOpen,
@@ -86,9 +86,9 @@ export function PromptSuggestions({ inputRef, isOpen, suggestions, setIsOpen, on
8686
};
8787
});
8888

89-
const visibleSuggestions = useMemo(() => suggestions.slice(0, ITEMS_MAX_LENGTH), [suggestions]);
89+
const visibleExamples = useMemo(() => examples.slice(0, ITEMS_MAX_LENGTH), [examples]);
9090

91-
if (!suggestions.length) {
91+
if (!examples.length) {
9292
return;
9393
}
9494

@@ -100,7 +100,7 @@ export function PromptSuggestions({ inputRef, isOpen, suggestions, setIsOpen, on
100100
{isOpen && (
101101
<FloatingPortal>
102102
<div ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
103-
<Container size="md" className={classes.root}>
103+
<Container size="sm" className={classes.root}>
104104
<motion.div
105105
{...fadeProps({
106106
hidden: {
@@ -115,9 +115,9 @@ export function PromptSuggestions({ inputRef, isOpen, suggestions, setIsOpen, on
115115
<h3 className={classes.heading}>Suggested</h3>
116116

117117
<ul className={classes.list}>
118-
{visibleSuggestions.map((prompt, idx) => (
118+
{visibleExamples.map((prompt, idx) => (
119119
<li key={idx} className={classes.item}>
120-
<SuggestionButton content={prompt} onSubmit={onSubmit} />
120+
<ExampleButton content={prompt} onSubmit={onSubmit} />
121121
</li>
122122
))}
123123
</ul>
@@ -132,7 +132,7 @@ export function PromptSuggestions({ inputRef, isOpen, suggestions, setIsOpen, on
132132
);
133133
}
134134

135-
function SuggestionButton({ content, onSubmit }: { content: string; onSubmit: (input: string) => void }) {
135+
function ExampleButton({ content, onSubmit }: { content: string; onSubmit: (input: string) => void }) {
136136
const ref = useRef<HTMLSpanElement>(null);
137137
const [isTruncated, setIsTruncated] = useState(false);
138138

@@ -191,7 +191,7 @@ function SuggestionButton({ content, onSubmit }: { content: string; onSubmit: (i
191191
}
192192

193193
const OFFSET = {
194-
mainAxis: 27, // Space between the input and the suggestions
194+
mainAxis: 27, // Space between the input and the examples
195195
};
196196

197197
const ITEMS_MAX_LENGTH = 5;

apps/beeai-ui/src/modules/runs/components/RunInput.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ import { dispatchInputEventOnTextarea, submitFormOnEnter } from '#utils/form-uti
1616
import { ChatDefaultTools } from '../chat/constants';
1717
import { useAgentRun } from '../contexts/agent-run';
1818
import type { RunAgentFormValues } from '../types';
19-
import { PromptSuggestions } from './PromptSuggestions';
19+
import { PromptExamples } from './PromptExamples';
2020
import { RunFiles } from './RunFiles';
2121
import classes from './RunInput.module.scss';
2222
// import { RunSettings } from './RunSettings';
2323
import { RunSubmit } from './RunSubmit';
2424

2525
interface Props {
26-
promptSuggestions?: string[];
26+
promptExamples?: string[];
2727
onSubmit?: () => void;
2828
}
2929

30-
export function RunInput({ promptSuggestions, onSubmit }: Props) {
30+
export function RunInput({ promptExamples, onSubmit }: Props) {
3131
const formRef = useRef<HTMLFormElement>(null);
3232
const inputRef = useRef<HTMLTextAreaElement>(null);
3333

34-
const [promptSuggestionsOpen, setPromptSuggestionsOpen] = useState(false);
34+
const [promptExamplesOpen, setPromptExamplesOpen] = useState(false);
3535

3636
const {
3737
agent: {
@@ -79,7 +79,7 @@ export function RunInput({ promptSuggestions, onSubmit }: Props) {
7979
const fillWithInput = useCallback(
8080
(value: string) => {
8181
setValue('input', value, { shouldValidate: true });
82-
setPromptSuggestionsOpen(false);
82+
setPromptExamplesOpen(false);
8383
dispatchInputEventAndFocus();
8484
},
8585
[setValue, dispatchInputEventAndFocus],
@@ -135,12 +135,12 @@ export function RunInput({ promptSuggestions, onSubmit }: Props) {
135135
</div>
136136
</div>
137137

138-
{promptSuggestions && (
139-
<PromptSuggestions
138+
{promptExamples && (
139+
<PromptExamples
140140
inputRef={inputRef}
141-
suggestions={promptSuggestions}
142-
isOpen={promptSuggestionsOpen}
143-
setIsOpen={setPromptSuggestionsOpen}
141+
examples={promptExamples}
142+
isOpen={promptExamplesOpen}
143+
setIsOpen={setPromptExamplesOpen}
144144
onSubmit={fillWithInput}
145145
/>
146146
)}

apps/beeai-ui/src/modules/runs/components/RunLandingView.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import { useMemo } from 'react';
7+
68
import { Container } from '#components/layouts/Container.tsx';
79
import { AgentGreeting } from '#modules/agents/components/AgentGreeting.tsx';
10+
import { getAgentPromptExamples } from '#modules/agents/utils.ts';
811

912
import { FileUpload } from '../../files/components/FileUpload';
1013
import { useAgentRun } from '../contexts/agent-run';
@@ -13,16 +16,15 @@ import classes from './RunLandingView.module.scss';
1316

1417
export function RunLandingView() {
1518
const { agent } = useAgentRun();
16-
const {
17-
ui: { starter_prompts },
18-
} = agent;
19+
20+
const promptExamples = useMemo(() => getAgentPromptExamples(agent), [agent]);
1921

2022
return (
2123
<FileUpload>
2224
<Container size="sm" className={classes.root}>
2325
<AgentGreeting agent={agent} />
2426

25-
<RunInput promptSuggestions={starter_prompts} />
27+
<RunInput promptExamples={promptExamples} />
2628
</Container>
2729
</FileUpload>
2830
);

0 commit comments

Comments
 (0)