Skip to content

Commit 12e46dd

Browse files
authored
Merge pull request #285 from l3vels/feat/system-message-template-system
feat: add templating system in system message builder
2 parents 29295ae + 9f5ea63 commit 12e46dd

File tree

14 files changed

+154
-51
lines changed

14 files changed

+154
-51
lines changed

apps/server/controllers/agent.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
from typings.auth import UserAccount
1212
from utils.agent import convert_agents_to_agent_list, convert_model_to_response
1313
from utils.auth import authenticate
14+
from utils.system_message import SystemMessageBuilder
1415

1516
# Standard library imports
1617

1718

18-
19-
2019
router = APIRouter()
2120

2221

@@ -213,7 +212,10 @@ def get_agent_by_id(
213212
status_code=404, detail="Agent not found"
214213
) # Ensure consistent case in error messages
215214

216-
return convert_model_to_response(db_agent, is_system_message)
215+
agent_with_configs = convert_model_to_response(db_agent)
216+
system_message = SystemMessageBuilder(agent_with_configs).build()
217+
agent_with_configs.system_message = system_message
218+
return agent_with_configs
217219

218220

219221
@router.get("/discover/{id}", response_model=AgentWithConfigsOutput)

apps/server/models/agent.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class AgentModel(BaseModel):
3434
# __abstract__ = True
3535
__tablename__ = "agent"
3636
id = Column(UUID, primary_key=True, index=True, default=uuid.uuid4)
37-
name = Column(String)
37+
name = Column(String, index=True)
3838
avatar = Column(String(300), default=None)
3939
role = Column(String)
4040
parent_id = Column(
@@ -249,6 +249,22 @@ def get_public_agents(cls, db):
249249
)
250250
return agents
251251

252+
@classmethod
253+
def get_agent_by_name(cls, session, account_id: UUID, agent_name: str):
254+
agent = (
255+
session.query(AgentModel)
256+
.outerjoin(UserModel, AgentModel.created_by == UserModel.id)
257+
.filter(
258+
AgentModel.account_id == account_id,
259+
AgentModel.is_deleted.is_(False),
260+
AgentModel.name.ilike(f"%{agent_name}%"),
261+
)
262+
.options(joinedload(AgentModel.configs))
263+
.options(joinedload(AgentModel.creator))
264+
.first()
265+
)
266+
return agent
267+
252268
@classmethod
253269
def get_agent_by_id(cls, db, agent_id):
254270
"""

apps/server/utils/agent.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@
22

33
from models.agent import AgentModel
44
from typings.agent import AgentOutput, AgentWithConfigsOutput, ConfigsOutput
5-
from utils.system_message import SystemMessageBuilder
65
from utils.type import convert_value_to_type
76
from utils.user import \
87
convert_model_to_response as user_convert_model_to_response
98

109

11-
def convert_model_to_response(
12-
agent_model: AgentModel, is_system_message: bool = False
13-
) -> AgentWithConfigsOutput:
10+
def convert_model_to_response(agent_model: AgentModel) -> AgentWithConfigsOutput:
1411
agent_data = {}
1512

1613
# Extract attributes from AgentModel using annotations of Agent
@@ -43,9 +40,6 @@ def convert_model_to_response(
4340
agent=AgentOutput(**agent_data),
4441
configs=ConfigsOutput(**configs) if configs else None,
4542
)
46-
if is_system_message:
47-
system_message = SystemMessageBuilder(agent_with_config).build()
48-
agent_with_config.system_message = system_message
4943

5044
return agent_with_config
5145

apps/server/utils/system_message.py

+56
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import re
12
from typing import List, Optional
23

4+
from fastapi_sqlalchemy import db
5+
6+
from models.agent import AgentModel
37
from typings.agent import AgentWithConfigsOutput
8+
from utils.agent import convert_model_to_response
49

510

611
class SystemMessageBuilder:
@@ -24,6 +29,7 @@ def build(self) -> str:
2429
context = self.build_pre_retrieved_context(self.pre_retrieved_context)
2530

2631
result = f"{base_system_message}{role}{description}{goals}{instructions}{constraints}{context}"
32+
result = self.replace_templates(result)
2733
return result
2834

2935
def build_base_system_message(self, text: str) -> str:
@@ -80,3 +86,53 @@ def build_pre_retrieved_context(self, text: str):
8086
result = "CONTEXT DATA: \n" f"{text}\n"
8187

8288
return result
89+
90+
def replace_templates(self, text: str) -> str:
91+
# This pattern will match strings like {{agent.sales.greeting}} and {{greeting}}
92+
pattern = re.compile(
93+
r"\{\{(agent\.(?P<agent_name>[\w\s]+?)\.)?(?P<field_name>\w+)(\[(?P<index>\d+)\])?\}\}"
94+
)
95+
96+
def replace_match(match):
97+
agent_name = match.group("agent_name")
98+
field_name = match.group("field_name")
99+
index = match.group("index")
100+
101+
if agent_name:
102+
# Fetch agent by name
103+
agent = AgentModel.get_agent_by_name(
104+
db.session, self.agent.account_id, agent_name
105+
)
106+
agent_data = convert_model_to_response(agent)
107+
source_data = (
108+
agent_data.agent
109+
if hasattr(agent_data.agent, field_name)
110+
else agent_data.configs
111+
)
112+
else:
113+
# Use current agent if no agent name is provided
114+
source_data = (
115+
self.agent if hasattr(self.agent, field_name) else self.configs
116+
)
117+
118+
if not source_data:
119+
return match.group(
120+
0
121+
) # Return the original text if agent or property not found
122+
123+
# Retrieve the field value
124+
value = getattr(source_data, field_name, "Unknown field")
125+
if index and isinstance(value, list):
126+
try:
127+
value = value[int(index)]
128+
except IndexError:
129+
value = "Index out of range"
130+
elif isinstance(value, list):
131+
# Format the list for display
132+
value = f"{field_name.upper()}: \n" + "\n".join(
133+
f"- {item}" for item in value
134+
)
135+
136+
return str(value)
137+
138+
return pattern.sub(replace_match, text)

apps/ui/src/gql/ai/agent/agentById.gql

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ query agentById($id: id!) @api(name: "ai") {
22
agentById(id: $id) @rest(type: "Agent", path: "/agent/{args.id}", method: "GET", endpoint: "ai") {
33
agent
44
configs
5+
system_message
56
}
67
}

apps/ui/src/i18n/locales/en.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -337,5 +337,6 @@
337337
"input-mode": "Input Mode",
338338
"output": "Output",
339339
"error": "Error",
340-
"similarity-top-k": "Similarity Top K"
340+
"similarity-top-k": "Similarity Top K",
341+
"system-message": "System Message"
341342
}

apps/ui/src/modals/AgentViewModal.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import IconButton from '@l3-lib/ui-core/dist/IconButton'
99

1010
import Close from '@l3-lib/ui-core/dist/icons/Close'
1111
import { useDiscoverAgentByIdService } from 'services/discover/useDiscoverAgentById'
12+
import { useAgentByIdService } from 'services/agent/useAgentByIdService'
13+
import { AgentWithConfigs } from 'types'
1214

1315
type AgentViewModalProps = {
1416
data: {
1517
id: string
16-
agent: any
18+
agent: AgentWithConfigs
1719
}
1820
}
1921

@@ -22,6 +24,8 @@ const AgentViewModal = ({ data }: AgentViewModalProps) => {
2224

2325
const { id, agent } = data
2426

27+
const { data: agentObj } = useAgentByIdService({ id: agent.agent.id })
28+
2529
const { data: agentById } = useDiscoverAgentByIdService({ id: id })
2630

2731
return (
@@ -33,7 +37,7 @@ const AgentViewModal = ({ data }: AgentViewModalProps) => {
3337
hideCloseButton
3438
>
3539
<StyledModalBody>
36-
<AgentView agentData={agentById || agent} />
40+
<AgentView agentData={agentObj || agentById || agent} />
3741
</StyledModalBody>
3842

3943
<StyledButtonWrapper>

apps/ui/src/pages/Agents/AgentCard/AgentCard.tsx

+2-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import TypographyPrimary from 'components/Typography/Primary'
2121
import TypographyTertiary from 'components/Typography/Tertiary'
2222
import { ButtonPrimary } from 'components/Button/Button'
2323
import { textSlicer } from 'utils/textSlicer'
24+
import { AgentWithConfigs } from 'types'
2425

2526
type AgentCardProps = {
2627
name: string
@@ -32,14 +33,13 @@ type AgentCardProps = {
3233
onViewClick: () => void
3334
onChatClick?: () => void
3435
onCreateClick?: () => void
35-
creator?: any
36+
creator?: AgentWithConfigs['agent']['creator']
3637
avatar?: string
3738
}
3839

3940
const AgentCard = ({
4041
name,
4142
description,
42-
// headerText,
4343
headerTag,
4444
onDeleteClick,
4545
onEditClick,
@@ -82,15 +82,6 @@ const AgentCard = ({
8282
)}
8383
</div>
8484
</StyledTitleWrapper>
85-
{/* <div>
86-
{headerText && (
87-
<TypographySecondary
88-
value={headerText}
89-
type={Typography.types.P}
90-
size={Typography.sizes.sm}
91-
/>
92-
)}
93-
</div> */}
9485
</StyledCardHeader>
9586
<StyledCardBody>
9687
<StyledBodyTextWrapper>
@@ -104,7 +95,6 @@ const AgentCard = ({
10495
<StyledCardFooter className='cardFooter'>
10596
{creator && (
10697
<StyledCreatorWrapper>
107-
{/* <StyledLogo src={l3Logo} /> */}
10898
<AvatarGenerator
10999
name={creator.name}
110100
size={16}
@@ -126,7 +116,6 @@ const AgentCard = ({
126116
icon={() => <StyledDeleteIcon />}
127117
size={Button.sizes.SMALL}
128118
kind={IconButton.kinds.TERTIARY}
129-
// ariaLabel='Delete'
130119
/>
131120
)}
132121
{onEditClick && (
@@ -135,7 +124,6 @@ const AgentCard = ({
135124
icon={() => <StyledEditIcon />}
136125
size={IconButton.sizes.SMALL}
137126
kind={IconButton.kinds.TERTIARY}
138-
// ariaLabel='Edit'
139127
/>
140128
)}
141129
{onViewClick && (
@@ -148,7 +136,6 @@ const AgentCard = ({
148136
)}
149137
size={Button.sizes.SMALL}
150138
kind={IconButton.kinds.TERTIARY}
151-
// ariaLabel='View'
152139
/>
153140
)}
154141
{onCreateClick && (

apps/ui/src/pages/Agents/AgentView/AgentView.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ import AgentToolkits from './components/AgentToolkits'
1919
import AgentDatasources from './components/AgentDatasources'
2020

2121
import AgentVIewDetailBox from './components/AgentViewDetailBox'
22+
import { AgentWithConfigs } from 'types'
2223

23-
const AgentView = ({ agentData }: { agentData?: any }) => {
24+
const AgentView = ({ agentData }: { agentData?: AgentWithConfigs }) => {
2425
const { t } = useTranslation()
2526
const params = useParams()
2627
const { agentId } = params
2728
const { data: agentById } = useAgentByIdService({ id: agentId || '' })
2829

29-
if (!agentById && !agentData) return <div />
30+
const agent = agentById || agentData
31+
if (!agent) return <div />
3032

31-
const { configs } = agentById || agentData
33+
const { configs, system_message } = agent
3234

3335
const { tools, goals, constraints, instructions, datasources, suggestions, greeting, text } =
3436
configs
@@ -51,13 +53,17 @@ const AgentView = ({ agentData }: { agentData?: any }) => {
5153
</>
5254
)}
5355
</StyledHeaderGroup>
54-
<ComponentsWrapper noPadding hideBox={agentData}>
55-
<StyledInnerWrapper noPadding={agentData}>
56+
<ComponentsWrapper noPadding hideBox={!!agentData}>
57+
<StyledInnerWrapper noPadding={!!agentData}>
5658
<StyledLeftColumn>
57-
<AgentVIewDetailBox agentData={agentById || agentData} />
59+
<AgentVIewDetailBox agentData={agent} />
5860
</StyledLeftColumn>
5961

6062
<StyledRightColumn>
63+
{system_message?.length ? (
64+
<AdditionalInfoBox items={[system_message]} title={t('system-message')} />
65+
) : null}
66+
6167
{tools?.length > 0 && <AgentToolkits tools={tools} />}
6268

6369
{datasources?.length > 0 && <AgentDatasources datasources={datasources} />}

apps/ui/src/pages/Agents/Agents.tsx

+6-13
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import ComponentsWrapper from 'components/ComponentsWrapper/ComponentsWrapper'
66
import {
77
StyledHeaderGroup,
88
StyledSectionDescription,
9-
StyledSectionTitle,
109
StyledSectionWrapper,
1110
} from 'pages/Home/homeStyle.css'
1211

@@ -18,12 +17,13 @@ import { ButtonPrimary } from 'components/Button/Button'
1817
import HeadingPrimary from 'components/Heading/Primary'
1918
import Heading from '@l3-lib/ui-core/dist/Heading'
2019
import { useGetAccountModule } from 'utils/useGetAccountModule'
20+
import { AgentWithConfigs } from 'types'
2121

2222
const Agents = ({ isHome }: { isHome?: boolean }) => {
2323
const { t } = useTranslation()
2424
const { getChatModules } = useGetAccountModule()
25-
const agentModule = getChatModules('agent')
2625

26+
const agentModule = getChatModules('agent')
2727
const { agentsData, deleteAgentHandler } = useAgents()
2828

2929
const navigate = useNavigate()
@@ -39,13 +39,6 @@ const Agents = ({ isHome }: { isHome?: boolean }) => {
3939
/>
4040
<StyledSectionDescription>{`${t('agent-description')}`}</StyledSectionDescription>
4141
</StyledMainHeaderWrapper>
42-
{/* <div>
43-
44-
<StyledSectionTitle>Agents</StyledSectionTitle>
45-
<StyledSectionDescription>
46-
Here are all your agents, managing tasks and operations.
47-
</StyledSectionDescription>
48-
</div> */}
4942

5043
<div>
5144
{!isHome && (
@@ -58,10 +51,11 @@ const Agents = ({ isHome }: { isHome?: boolean }) => {
5851
)}
5952
</div>
6053
</StyledHeaderGroup>
54+
6155
<ComponentsWrapper noPadding>
6256
<StyledCardsWrapper>
63-
{agentsData?.map((agentObj: any, index: number) => {
64-
const { agent } = agentObj
57+
{agentsData?.map((agentWithConfigs: AgentWithConfigs, index: number) => {
58+
const { agent } = agentWithConfigs
6559

6660
const handleEdit = () => {
6761
navigate(`/agents/${agent.id}/edit-agent`)
@@ -99,14 +93,13 @@ export const StyledCardsWrapper = styled.div`
9993
align-items: center;
10094
flex-wrap: wrap;
10195
gap: 16px;
102-
103-
/* max-width: 1055px; */
10496
width: 100%;
10597
max-height: calc(100vh - 325px);
10698
height: 100%;
10799
overflow-y: auto;
108100
padding: 5px 32px;
109101
`
102+
110103
const StyledMainHeaderWrapper = styled.div`
111104
display: flex;
112105
width: 100%;

0 commit comments

Comments
 (0)