Skip to content

Commit 52ae5fb

Browse files
authored
feat(agent-ui): add embed-frame support for nav items (#1761)
1 parent f015439 commit 52ae5fb

File tree

17 files changed

+983
-130
lines changed

17 files changed

+983
-130
lines changed

multimodal/omni-tars/omni-agent/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,14 @@ export default class OmniTARSAgent extends ComposableAgent {
205205
title: 'Code Server',
206206
link: sandboxBaseUrl + '/code-server/',
207207
icon: 'code',
208+
behavior: 'new-page',
208209
},
209210
{
210211
title: 'VNC',
211212
link: sandboxBaseUrl + '/vnc/index.html?autoconnect=true',
212213
icon: 'monitor',
214+
behavior: 'embed-frame',
215+
autoActive: true,
213216
},
214217
],
215218
},
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Runtime Settings-based AutoActive Feature
2+
3+
## Overview
4+
5+
The `autoActive` property in `workspace.navItems` supports dynamic evaluation based on `api/v1/runtime-settings` values, enabling conditional auto-activation of embedded frames.
6+
7+
## How It Works
8+
9+
### autoActive Design Logic
10+
11+
1. **Backward Compatibility**: `autoActive?: boolean` works as before
12+
2. **String Expressions**: `autoActive?: string` accepts JavaScript expressions
13+
3. **Dynamic Evaluation**: Navbar fetches runtime settings and evaluates expressions in real-time
14+
4. **Safe Execution**: Uses `new Function()` with limited scope for security
15+
16+
### Runtime Settings Consumption
17+
18+
1. **API Endpoint**: `apiService.getSessionRuntimeSettings(sessionId)` returns current settings
19+
2. **Data Structure**: `{ currentValues: Record<string, any> }` contains user settings
20+
3. **Real-time Updates**: Refetched when session changes
21+
4. **Expression Context**: Runtime settings passed as `runtimeSettings` parameter
22+
23+
## Usage Examples
24+
25+
### Basic Boolean (Backward Compatible)
26+
```json
27+
{
28+
"workspace": {
29+
"navItems": [
30+
{
31+
"title": "Code Server",
32+
"link": "{prefix}/code-server/",
33+
"icon": "code",
34+
"behavior": "embed-frame",
35+
"autoActive": true
36+
}
37+
]
38+
}
39+
}
40+
```
41+
42+
### Dynamic Expression
43+
```json
44+
{
45+
"workspace": {
46+
"navItems": [
47+
{
48+
"title": "VNC",
49+
"link": "{prefix}/vnc/index.html?autoconnect=true",
50+
"icon": "monitor",
51+
"behavior": "embed-frame",
52+
"autoActive": "runtimeSettings.agentMode === 'game'"
53+
}
54+
]
55+
}
56+
}
57+
```
58+
59+
## Real-world Example
60+
61+
From `examples/webui-config.json`:
62+
```json
63+
{
64+
"workspace": {
65+
"navItems": [
66+
{
67+
"title": "Code Server",
68+
"link": "{prefix}/code-server/",
69+
"icon": "code",
70+
"behavior": "embed-frame"
71+
},
72+
{
73+
"title": "VNC",
74+
"link": "{prefix}/vnc/index.html?autoconnect=true",
75+
"icon": "monitor",
76+
"behavior": "embed-frame",
77+
"autoActive": "debug(runtimeSettings) && runtimeSettings.agentMode === 'game'"
78+
}
79+
]
80+
}
81+
}
82+
```
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
{
2+
"logo": "https://lf3-static.bytednsdoc.com/obj/eden-cn/zyha-aulnh/ljhwZthlaukjlkulzlp/icon.png",
3+
"title": "Omni Agent",
4+
"subtitle": "Offering seamless integration with a wide range of real-world tools.",
5+
"welcomTitle": "Let’s work it out",
6+
"welcomePrompts": [],
7+
"welcomeCards": [
8+
{
9+
"title": "2048",
10+
"category": "Game",
11+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/cb8c967c-4a78-4ffa-8506-cbac69746f4f/2048.png",
12+
"agentOptions": {
13+
"agentMode": {
14+
"id": "game",
15+
"link": "https://poki.com/zh/g/2048",
16+
"browserMode": "hybrid"
17+
}
18+
}
19+
},
20+
{
21+
"title": "Four in a Row",
22+
"category": "Game",
23+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/e80686db-b0fb-4f2c-bd2f-3a89734f102a/four-in-a-row.jpg",
24+
"agentOptions": {
25+
"agentMode": {
26+
"id": "game",
27+
"link": "https://poki.com/zh/g/four-in-a-row",
28+
"browserMode": "hybrid"
29+
}
30+
}
31+
},
32+
{
33+
"title": "Block the Pig",
34+
"category": "Game",
35+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/9fec1234ce2afd5e789f56da463dcffc/block-the-pig.jpeg",
36+
"agentOptions": {
37+
"agentMode": {
38+
"id": "game",
39+
"link": "https://poki.com/zh/g/block-the-pig",
40+
"browserMode": "hybrid"
41+
}
42+
}
43+
},
44+
{
45+
"title": "Factory Balls Forever",
46+
"category": "Game",
47+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/2a503d0a1d9475d6e62c7ea11caa429ab952aa8f500755613a34e66e2196fe82/factory-balls-forever.png",
48+
"agentOptions": {
49+
"agentMode": {
50+
"id": "game",
51+
"link": "https://poki.com/zh/g/factory-balls-forever",
52+
"browserMode": "hybrid"
53+
}
54+
}
55+
},
56+
{
57+
"title": "Snake Solver",
58+
"category": "Game",
59+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/e466baf845544ef47e0dfbd60f127071/snake-solver.png",
60+
"agentOptions": {
61+
"agentMode": {
62+
"id": "game",
63+
"link": "https://poki.com/zh/g/snake-solver",
64+
"browserMode": "hybrid"
65+
}
66+
}
67+
},
68+
{
69+
"title": "Penalty Kicks",
70+
"category": "Game",
71+
"image": "https://img.poki-cdn.com/cdn-cgi/image/q=78,scq=50,width=80,height=80,fit=cover,f=auto/0770daaa8c4ff3c36dd53e6e41f59396/penalty-kicks.png",
72+
"agentOptions": {
73+
"agentMode": {
74+
"id": "game",
75+
"link": "https://poki.com/zh/g/penalty-kicks",
76+
"browserMode": "hybrid"
77+
}
78+
}
79+
},
80+
{
81+
"title": "GUI Agent Research",
82+
"category": "Research",
83+
"prompt": "Search for the latest GUI Agent papers",
84+
"image": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=400&h=300&fit=crop&crop=center"
85+
},
86+
{
87+
"title": "UI TARS Information",
88+
"category": "Research",
89+
"prompt": "Find information about UI TARS",
90+
"image": "https://images.unsplash.com/photo-1561070791-2526d30994b5?w=400&h=300&fit=crop&crop=center"
91+
},
92+
{
93+
"title": "ProductHunt Trends",
94+
"category": "Research",
95+
"prompt": "Tell me the top 5 most popular projects on ProductHunt today",
96+
"image": "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=400&h=300&fit=crop&crop=center"
97+
},
98+
{
99+
"title": "Python Hello World",
100+
"category": "Code",
101+
"prompt": "Write hello world using python",
102+
"image": "https://images.unsplash.com/photo-1526379095098-d400fd0bf935?w=400&h=300&fit=crop&crop=center"
103+
},
104+
{
105+
"title": "Jupyter Math Comparison",
106+
"category": "Code",
107+
"prompt": "Use jupyter to calculate which is greater in 9.11 and 9.9",
108+
"image": "https://images.unsplash.com/photo-1635070041078-e363dbe005cb?w=400&h=300&fit=crop&crop=center"
109+
},
110+
{
111+
"title": "Reproduce Seed-TARS",
112+
"category": "Code",
113+
"prompt": "Write code to reproduce seed-tars.com",
114+
"image": "https://images.unsplash.com/photo-1627398242454-45a1465c2479?w=400&h=300&fit=crop&crop=center"
115+
},
116+
{
117+
"title": "Seed-TARS Summary",
118+
"category": "Research",
119+
"prompt": "Summary seed-tars.com/1.5",
120+
"image": "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=300&fit=crop&crop=center"
121+
},
122+
{
123+
"title": "PDF to Markdown Converter",
124+
"category": "Code",
125+
"prompt": "Write a python code to download the paper https://arxiv.org/abs/2505.12370, and convert the pdf to markdown",
126+
"image": "https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=400&h=300&fit=crop&crop=center"
127+
},
128+
{
129+
"title": "ByteDance News Website",
130+
"category": "Code",
131+
"prompt": "Search news about bytedance seed1.6 model, then write a web page in modern style and deploy it",
132+
"image": "https://images.unsplash.com/photo-1504711434969-e33886168f5c?w=400&h=300&fit=crop&crop=center"
133+
},
134+
{
135+
"title": "Transformer Code Sample",
136+
"category": "Code",
137+
"prompt": "Write a minimal code sample to help me use transformer",
138+
"image": "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?w=400&h=300&fit=crop&crop=center"
139+
},
140+
{
141+
"title": "HuggingFace Dataset Analysis",
142+
"category": "Research",
143+
"prompt": "Please search for trending datasets on Hugging Face, download the top-ranked dataset, and calculate the total number of characters in the entire dataset.",
144+
"image": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=400&h=300&fit=crop&crop=center"
145+
},
146+
{
147+
"title": "Political History Analysis",
148+
"category": "Research",
149+
"prompt": "Identify the independence process of a twin-island nation where the pro-self-governance political group won thirteen out of seventeen legislative seats in spring 1980 national polls, a second constitutional conference was held at a historic London venue in late 1980, liberation from colonial rule is annually commemorated on November 1st as a public holiday, and an agreement revised the smaller island's local governance legislation for enhanced autonomy. What was the composition of the associated state that preceded its independence?",
150+
"image": "https://images.unsplash.com/photo-1529107386315-e1a2ed48a620?w=400&h=300&fit=crop&crop=center"
151+
},
152+
{
153+
"title": "Music Theory Course Builder",
154+
"category": "Research",
155+
"prompt": "I am a high school music theory teacher and i'm preparing a course on basic music theory to explain knowledge about music names, roll titles, major scales, octave distribution, and physical frequency. Please help me collect enough informations, design fulfilling and authoritative course content with demonstration animations, and finally output them as web page",
156+
"image": "https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=400&h=300&fit=crop&crop=center"
157+
}
158+
],
159+
"workspace": {
160+
"navItems": [
161+
{
162+
"title": "Code Server",
163+
"link": "{prefix}/code-server/",
164+
"icon": "code",
165+
"behavior": "embed-frame"
166+
},
167+
{
168+
"title": "VNC",
169+
"link": "{prefix}/vnc/index.html?autoconnect=true",
170+
"icon": "monitor",
171+
"behavior": "embed-frame",
172+
"autoActive": "runtimeSettings.agentMode === 'game'"
173+
}
174+
]
175+
},
176+
"guiAgent": {
177+
"defaultScreenshotRenderStrategy": "afterAction",
178+
"enableScreenshotRenderStrategySwitch": true,
179+
"renderGUIAction": true,
180+
"renderBrowserShell": false
181+
},
182+
"layout": {
183+
"enableLayoutSwitchButton": true
184+
}
185+
}

multimodal/tarko/agent-ui/src/common/hooks/useSession.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import { messagesAtom, groupedMessagesAtom } from '../state/atoms/message';
44
import { toolResultsAtom } from '../state/atoms/tool';
55

66
import { sessionFilesAtom } from '../state/atoms/files';
7-
import { isProcessingAtom, activePanelContentAtom, connectionStatusAtom } from '../state/atoms/ui';
7+
import {
8+
isProcessingAtom,
9+
activePanelContentAtom,
10+
connectionStatusAtom,
11+
activeEmbedFrameAtom,
12+
workspaceDisplayStateAtom,
13+
} from '../state/atoms/ui';
814
import { replayStateAtom } from '../state/atoms/replay';
915
import {
1016
loadSessionsAction,
@@ -35,6 +41,8 @@ export function useSession() {
3541
const [isProcessing, setIsProcessing] = useAtom(isProcessingAtom);
3642
const [activePanelContent, setActivePanelContent] = useAtom(activePanelContentAtom);
3743
const [connectionStatus, setConnectionStatus] = useAtom(connectionStatusAtom);
44+
const [activeEmbedFrame, setActiveEmbedFrame] = useAtom(activeEmbedFrameAtom);
45+
const [workspaceDisplayState, setWorkspaceDisplayState] = useAtom(workspaceDisplayStateAtom);
3846

3947
const [replayState, setReplayState] = useAtom(replayStateAtom);
4048

@@ -91,6 +99,8 @@ export function useSession() {
9199
isProcessing,
92100
activePanelContent,
93101
connectionStatus,
102+
activeEmbedFrame,
103+
workspaceDisplayState,
94104

95105
replayState,
96106
sessionMetadata,
@@ -106,6 +116,8 @@ export function useSession() {
106116
abortQuery,
107117

108118
setActivePanelContent,
119+
setActiveEmbedFrame,
120+
setWorkspaceDisplayState,
109121

110122
initConnectionMonitoring,
111123
checkServerStatus,
@@ -122,6 +134,8 @@ export function useSession() {
122134
isProcessing,
123135
activePanelContent,
124136
connectionStatus,
137+
activeEmbedFrame,
138+
workspaceDisplayState,
125139
replayState,
126140
sessionMetadata,
127141
loadSessions,
@@ -133,6 +147,8 @@ export function useSession() {
133147
sendMessage,
134148
abortQuery,
135149
setActivePanelContent,
150+
setActiveEmbedFrame,
151+
setWorkspaceDisplayState,
136152
initConnectionMonitoring,
137153
checkServerStatus,
138154
checkSessionStatus,

multimodal/tarko/agent-ui/src/common/state/actions/eventProcessors/handlers/SystemHandler.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { messagesAtom } from '@/common/state/atoms/message';
55
import { sessionPanelContentAtom } from '@/common/state/atoms/ui';
66
import { shouldUpdatePanelContent } from '../utils/panelContentUpdater';
77
import { ChatCompletionContentPartImage } from '@tarko/agent-interface';
8+
import { StandardPanelContent } from '@/standalone/workspace/types/index';
89

910
export class SystemMessageHandler implements EventHandler<AgentEventStream.SystemEvent> {
1011
canHandle(event: AgentEventStream.Event): event is AgentEventStream.SystemEvent {
@@ -91,21 +92,20 @@ export class EnvironmentInputHandler
9192
const currentSessionPanel = currentPanelContent[sessionId];
9293

9394
// Common panel properties
94-
const basePanelContent = {
95+
const basePanelContent: Partial<StandardPanelContent> = {
9596
title: event.description || 'Environment Screenshot',
9697
timestamp: event.timestamp,
97-
originalContent: event.content,
9898
environmentId: event.id,
9999
};
100100

101-
let panelContent = null;
101+
let panelContent: StandardPanelContent | null = null;
102102

103103
if (isFirstEnvironmentInput) {
104104
// First environment input: always show as simple image
105105
panelContent = {
106106
...basePanelContent,
107107
type: 'image',
108-
source: imageContent.image_url.url,
108+
source: imageContent.image_url.url as string,
109109
};
110110
} else if (
111111
currentSessionPanel?.type === 'browser_vision_control' ||
@@ -115,7 +115,7 @@ export class EnvironmentInputHandler
115115
panelContent = {
116116
...basePanelContent,
117117
type: 'browser_vision_control',
118-
source: null,
118+
source: undefined,
119119
title: event.description || 'Browser Screenshot',
120120
};
121121
}

0 commit comments

Comments
 (0)