Skip to content

Commit 77380ca

Browse files
authored
Merge branch 'main' into stas/retry-grant
2 parents 1210938 + b63209c commit 77380ca

9 files changed

Lines changed: 185 additions & 38 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"ruff.fixAll": true,
1313
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
1414
"python.terminal.activateEnvironment": true,
15-
"python.languageServer": "Pylance",
15+
"python.languageServer": "None",
1616
"editor.defaultFormatter": "esbenp.prettier-vscode",
1717
"editor.formatOnSave": true,
1818
"editor.codeActionsOnSave": {

agentex-ui/app/page.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { connection } from 'next/server';
22

33
import { AgentexUIRoot } from '@/components/agentex-ui-root';
4+
import { AgentexProvider } from '@/components/providers';
45

56
export default async function RootPage() {
67
await connection();
@@ -19,9 +20,11 @@ export default async function RootPage() {
1920
}
2021

2122
return (
22-
<AgentexUIRoot
23+
<AgentexProvider
2324
sgpAppURL={sgpAppURL}
2425
agentexAPIBaseURL={agentexAPIBaseURL}
25-
/>
26+
>
27+
<AgentexUIRoot />
28+
</AgentexProvider>
2629
);
2730
}

agentex-ui/components/agentex-ui-root.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,41 @@ import { useCallback, useEffect, useState } from 'react';
55
import { ToastContainer } from 'react-toastify';
66

77
import { PrimaryContent } from '@/components/primary-content/primary-content';
8-
import { AgentexProvider } from '@/components/providers';
8+
import { useAgentexClient } from '@/components/providers';
99
import { TaskSidebar } from '@/components/task-sidebar/task-sidebar';
1010
import { TracesSidebar } from '@/components/traces-sidebar/traces-sidebar';
11+
import { useAgents } from '@/hooks/use-agents';
1112
import { useLocalStorageState } from '@/hooks/use-local-storage-state';
1213
import {
1314
SearchParamKey,
1415
useSafeSearchParams,
1516
} from '@/hooks/use-safe-search-params';
1617

17-
type AgentexUIRootProps = {
18-
sgpAppURL: string;
19-
agentexAPIBaseURL: string;
20-
};
21-
22-
export function AgentexUIRoot({
23-
sgpAppURL,
24-
agentexAPIBaseURL,
25-
}: AgentexUIRootProps) {
18+
export function AgentexUIRoot() {
2619
const { agentName, taskID, updateParams } = useSafeSearchParams();
2720
const [isTracesSidebarOpen, setIsTracesSidebarOpen] = useState(false);
21+
const { agentexClient } = useAgentexClient();
22+
const { data: agents = [], isLoading } = useAgents(agentexClient);
2823
const [localAgentName, setLocalAgentName] = useLocalStorageState<
2924
string | undefined
3025
>('lastSelectedAgent', undefined);
3126

3227
useEffect(() => {
28+
if (isLoading) return;
29+
30+
const selectedAgent = agents.find(agent => agent.name === agentName);
31+
const isAgentValid = selectedAgent && selectedAgent.status === 'Ready';
32+
33+
if (!isAgentValid) {
34+
updateParams({ [SearchParamKey.AGENT_NAME]: null });
35+
setLocalAgentName(undefined);
36+
}
37+
3338
if (!agentName && localAgentName) {
3439
updateParams({ [SearchParamKey.AGENT_NAME]: localAgentName });
3540
}
3641
// eslint-disable-next-line react-hooks/exhaustive-deps
37-
}, []);
42+
}, [isLoading]);
3843

3944
const handleSelectTask = useCallback(
4045
(taskId: string | null) => {
@@ -70,21 +75,16 @@ export function AgentexUIRoot({
7075

7176
return (
7277
<>
73-
<AgentexProvider
74-
sgpAppURL={sgpAppURL ?? ''}
75-
agentexAPIBaseURL={agentexAPIBaseURL}
76-
>
77-
<div className="fixed inset-0 flex w-full">
78-
<TaskSidebar />
79-
<PrimaryContent
80-
isTracesSidebarOpen={isTracesSidebarOpen}
81-
toggleTracesSidebar={() =>
82-
setIsTracesSidebarOpen(!isTracesSidebarOpen)
83-
}
84-
/>
85-
<TracesSidebar isOpen={isTracesSidebarOpen} />
86-
</div>
87-
</AgentexProvider>
78+
<div className="fixed inset-0 flex w-full">
79+
<TaskSidebar />
80+
<PrimaryContent
81+
isTracesSidebarOpen={isTracesSidebarOpen}
82+
toggleTracesSidebar={() =>
83+
setIsTracesSidebarOpen(!isTracesSidebarOpen)
84+
}
85+
/>
86+
<TracesSidebar isOpen={isTracesSidebarOpen} />
87+
</div>
8888
<ToastContainer />
8989
</>
9090
);

agentex-ui/components/primary-content/chat-view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function ChatView({
6363
ref={headerRef}
6464
/>
6565

66-
<div className="flex min-h-full w-full flex-col items-center px-4 sm:px-6 md:px-8">
66+
<div className="flex w-full flex-col items-center px-4 sm:px-6 md:px-8">
6767
<div className="w-full max-w-3xl">
6868
<TaskProvider taskId={taskID}>
6969
<TaskMessages taskId={taskID} headerRef={headerRef} />

agentex-ui/components/task-header/task-header.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ export function TaskHeader({
8080
</SelectTrigger>
8181
<SelectContent>
8282
{agents.map(agent => (
83-
<SelectItem key={agent.name} value={agent.name}>
83+
<SelectItem
84+
key={agent.name}
85+
value={agent.name}
86+
disabled={agent.status !== 'Ready'}
87+
>
8488
{agent.name}
8589
</SelectItem>
8690
))}

agentex-ui/components/task-messages/task-message-reasoning-content.tsx

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { memo, useState, useMemo } from 'react';
1+
import { memo, useState, useMemo, useRef, useEffect } from 'react';
22

33
import { motion } from 'framer-motion';
44
import { BrainIcon, ChevronDownIcon } from 'lucide-react';
@@ -21,6 +21,9 @@ type TaskMessageReasoningProps = {
2121

2222
function TaskMessageReasoningImpl({ message }: TaskMessageReasoningProps) {
2323
const [isCollapsed, setIsCollapsed] = useState(true);
24+
const [showTopBlur, setShowTopBlur] = useState(false);
25+
const [showBottomBlur, setShowBottomBlur] = useState(false);
26+
const scrollContainerRef = useRef<HTMLDivElement>(null);
2427

2528
const { taskID } = useSafeSearchParams();
2629
const { agentexClient } = useAgentexClient();
@@ -61,6 +64,30 @@ function TaskMessageReasoningImpl({ message }: TaskMessageReasoningProps) {
6164
].join('\n\n');
6265
}, [message.content]);
6366

67+
const updateBlurEffects = () => {
68+
const container = scrollContainerRef.current;
69+
if (!container) return;
70+
71+
const { scrollTop, scrollHeight, clientHeight } = container;
72+
const isScrollable = scrollHeight > clientHeight;
73+
74+
setShowTopBlur(isScrollable && scrollTop > 10);
75+
setShowBottomBlur(
76+
isScrollable && scrollTop < scrollHeight - clientHeight - 10
77+
);
78+
};
79+
80+
useEffect(() => {
81+
const container = scrollContainerRef.current;
82+
if (!container) return;
83+
84+
updateBlurEffects();
85+
const resizeObserver = new ResizeObserver(updateBlurEffects);
86+
resizeObserver.observe(container);
87+
88+
return () => resizeObserver.disconnect();
89+
}, [isCollapsed, reasoningText]);
90+
6491
return (
6592
<motion.div
6693
className="w-full"
@@ -90,9 +117,29 @@ function TaskMessageReasoningImpl({ message }: TaskMessageReasoningProps) {
90117
/>
91118
</button>
92119
<Collapsible collapsed={isCollapsed}>
93-
<MarkdownResponse className="ml-6 grid border-l-4 border-gray-300 pl-3 text-gray-500">
94-
{reasoningText}
95-
</MarkdownResponse>
120+
<div className="relative ml-6">
121+
<div
122+
className={cn(
123+
'pointer-events-none absolute inset-x-0 top-0 z-10 h-8 bg-gradient-to-b from-white to-transparent transition-opacity',
124+
showTopBlur ? 'opacity-100' : 'opacity-0'
125+
)}
126+
/>
127+
<div
128+
ref={scrollContainerRef}
129+
onScroll={updateBlurEffects}
130+
className="max-h-48 overflow-y-auto"
131+
>
132+
<MarkdownResponse className="grid border-l-4 border-gray-300 pl-3 text-gray-500">
133+
{reasoningText}
134+
</MarkdownResponse>
135+
</div>
136+
<div
137+
className={cn(
138+
'pointer-events-none absolute inset-x-0 bottom-0 z-10 h-8 bg-gradient-to-t from-white to-transparent transition-opacity',
139+
showBottomBlur ? 'opacity-100' : 'opacity-0'
140+
)}
141+
/>
142+
</div>
96143
</Collapsible>
97144
</motion.div>
98145
);

agentex-ui/package-lock.json

Lines changed: 62 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Enterprise Edition
2+
3+
## Overview
4+
5+
Agentex Enterprise Edition offers enhanced capabilities to support, monitor, and evaluate Agentex agents. The video below gives a brief demo of the what the developer experience would look like with Agentex's enterprise features enabled
6+
7+
8+
<video controls width="100%" >
9+
<source src="https://github.com/user-attachments/assets/cccb6211-281c-49d5-b24c-6730ae576b14" type="video/mp4">
10+
</video>
11+
12+
## Why Open Source?
13+
14+
At Scale, we've spent the last three years building enterprise AI agents and learned how different every use case is. To unify our approach, we built a single delivery framework and now we're open-sourcing it to share what we've learned. Many enterprises have built upon open source tooling, and we want to contribute to that ecosystem. Our goal is simple: see more useful AI in production.
15+
16+
Agentex is also cloud-agnostic and Kubernetes-native. We intentionally kept it lightweight and unopinionated to maximize flexibility and to incur minimal infrastructure and security overhead.
17+
18+
Here are the differences between Open Source vs Enterprise to meet different organizational needs:
19+
20+
| Feature | Open Source Edition | Enterprise Edition |
21+
|---------|--------------------|--------------------|
22+
| **Source Code** | ✅ Open source server, developer UI, and SDK | ✅ Open source server, developer UI, and SDK |
23+
| **Local Development** | ✅ Use this repo for local development | ✅ Use this repo for local development |
24+
| **Community Support** | ✅ GitHub issues, discussions, pull requests | ✅ GitHub issues, discussions, pull requests |
25+
| **GitOps Setup** | ❌ DIY deployment using public helm charts and the `agentex` CLI in CI/CD | ✅ Scale sets up CI/CD on select repositories for automatic agent deployment |
26+
| **Builder Tools** | ❌ Bring your own (vector stores, models, etc.) | ✅ Model inference, knowledge bases, etc. |
27+
| **Agent Operations (AgentOps)** | ❌ Not included | ✅ Full agent lifecycle management: hosting, version control, interaction UI, tracing, evaluation |
28+
| **Identity Management** | ❌ No user management | ✅ SSO/SAML authentication, centralized API key management |
29+
| **Enterprise Operations** | ❌ Self-service setup | ✅ Uptime/availability SLAs, security reviews, deployment, installation, ongoing maintenance |
30+
31+
**Ready for Enterprise?** Contact our team at https://scale.com/demo to discuss your requirements.
32+
33+
> For our current and future customers, Agentex is a module that is hosted and deployed as part of the Scale GenAI Platform's Enterprise License. This open source project is meant to give people a local development ability and community support.

agentex/docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ nav:
7575
- State Machines: development_guides/state_machines.md
7676
- Agent Task Tracker: development_guides/agent_task_tracker.md
7777
- Webhooks: development_guides/webhooks.md
78+
- Enterprise Edition: development_guides/enterprise_edition.md
7879
- Temporal Development:
7980
- Overview: temporal_development/overview.md
8081
- Use Cases: temporal_development/use_cases.md

0 commit comments

Comments
 (0)