Skip to content

Commit a64f3ed

Browse files
sanyuan0704ulivz
authored andcommitted
feat: support artifact in replay process (#225)
1 parent d2b7b8d commit a64f3ed

File tree

11 files changed

+132
-24
lines changed

11 files changed

+132
-24
lines changed

apps/agent-tars/src/main/ipcRoutes/action.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import fs, { readFile } from 'fs-extra';
1010
import { shell } from 'electron';
1111
import fetch from 'node-fetch';
1212
import FormData from 'form-data';
13-
import { normalizeMessages } from '@main/utils/normalizeOmegaData';
13+
import {
14+
normalizeMessages,
15+
parseArtifacts,
16+
} from '@main/utils/normalizeOmegaData';
1417

1518
export interface MCPTool {
1619
id: string;
@@ -136,10 +139,14 @@ export const actionRoute = t.router({
136139
path.join(__dirname, '../reporter/index.html'),
137140
'utf-8',
138141
);
142+
const artifacts = await parseArtifacts(messages);
139143
const reportContent = reportHtmlTemplate.replace(
140144
' <!-- DATA -->',
141145
'<script>window.__OMEGA_REPORT_DATA__ = ' +
142-
JSON.stringify(messages) +
146+
JSON.stringify({
147+
messages,
148+
artifacts,
149+
}) +
143150
';</script>',
144151
);
145152

apps/agent-tars/src/main/llmProvider/providers/AnthropicProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export class AnthropicProvider extends BaseProvider {
3333
super(config);
3434

3535
// Use environment variables or defaults
36-
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
37-
const baseURL = config.baseURL || process.env.ANTHROPIC_API_BASE_URL;
36+
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY || '';
37+
const baseURL = config.baseURL || process.env.ANTHROPIC_API_BASE_URL || '';
3838

3939
if (!apiKey) {
4040
throw new Error(

apps/agent-tars/src/main/utils/normalizeOmegaData.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { readFile } from 'fs-extra';
2+
import path from 'path';
23

34
interface ImageItem {
45
type: 'image';
@@ -20,9 +21,12 @@ interface OmegaAgentMessage {
2021
};
2122
}
2223

23-
export async function normalizeMessages(
24-
messages: Array<OmegaAgentMessage | any>,
25-
) {
24+
function isImage(filePath: string): boolean {
25+
const ext = path.extname(filePath).toLowerCase();
26+
return ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'].includes(ext);
27+
}
28+
29+
export async function normalizeMessages(messages: Array<OmegaAgentMessage>) {
2630
const normalizedMessages = await Promise.all(
2731
messages.map(async (item) => {
2832
if (item.type !== 'omega-agent') {
@@ -89,3 +93,52 @@ export async function normalizeMessages(
8993

9094
return normalizedMessages;
9195
}
96+
97+
export async function parseArtifacts(messages: Array<OmegaAgentMessage>) {
98+
let artifacts: {
99+
[key: string]: {
100+
content: string;
101+
};
102+
} = {};
103+
104+
await Promise.all(
105+
messages.map(async (item) => {
106+
if (item.type !== 'omega-agent') {
107+
return;
108+
}
109+
110+
await Promise.all(
111+
item.content.events.map(async (event) => {
112+
if (event.type === 'chat-text') {
113+
const { attachments = [] } = event.content;
114+
await Promise.all(
115+
attachments.map(async (attachment) => {
116+
const artifactPath = attachment.path;
117+
const fileName = path.basename(artifactPath);
118+
119+
try {
120+
if (isImage(artifactPath)) {
121+
const base64Content = await readFile(
122+
artifactPath,
123+
'base64',
124+
);
125+
artifacts[fileName] = {
126+
content: `data:image/${path.extname(artifactPath).slice(1)};base64,${base64Content}`,
127+
};
128+
} else {
129+
const content = await readFile(artifactPath, 'utf-8');
130+
artifacts[fileName] = { content };
131+
}
132+
} catch (error) {
133+
console.error(`Failed to read file: ${artifactPath}`, error);
134+
}
135+
}),
136+
);
137+
}
138+
}),
139+
);
140+
}),
141+
);
142+
143+
return artifacts;
144+
}

apps/agent-tars/src/renderer/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
content="default-src 'self' 'unsafe-inline' file: data: blob:; img-src 'self' file: data: blob:; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net/npm/ https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; font-src 'self' https://cdnjs.cloudflare.com https://fonts.googleapis.com; worker-src 'self' blob:; connect-src 'self' https://cdn.jsdelivr.net/npm/ blob:"
99
/>
1010
</head>
11-
<!-- DATA -->
1211
<body>
1312
<div id="root"></div>
1413
<script type="module" src="/src/main.tsx"></script>
14+
<!-- DATA -->
1515
</body>
1616
</html>

apps/agent-tars/src/renderer/src/agent/Greeter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class Greeter {
7070
},
7171
});
7272
});
73-
} catch (error) {
73+
} catch (error: any) {
7474
console.log(error);
7575
throw error;
7676
}

apps/agent-tars/src/renderer/src/components/AgentApp/index.tsx

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,45 @@ import { useFileSystemSettings } from '@renderer/hooks/useFileSystemSettings';
1111

1212
export function AgentApp() {
1313
const [showCanvas] = useAtom(showCanvasAtom);
14-
// Initialize file system settings
14+
1515
useFileSystemSettings();
1616

17+
if (isReportHtmlMode) {
18+
return (
19+
<div className="w-full h-full flex">
20+
<div className="flex flex-1 w-full h-full overflow-hidden">
21+
<div
22+
className="flex-shrink-0"
23+
style={{ width: showCanvas ? '45%' : '100%' }}
24+
>
25+
<OpenAgentChatUI />
26+
</div>
27+
{showCanvas && (
28+
<div
29+
className="flex-shrink-0 bg-background border-l border-divider"
30+
style={{ width: '55%' }}
31+
>
32+
<CanvasPanel />
33+
</div>
34+
)}
35+
</div>
36+
<Toaster position="top-center" />
37+
<FilePermissionHandler />
38+
</div>
39+
);
40+
}
41+
1742
return (
1843
<div className="w-full h-full flex">
19-
{!isReportHtmlMode ? (
20-
<div>
21-
<LeftSidebar />
22-
</div>
23-
) : null}
44+
<div>
45+
<LeftSidebar />
46+
</div>
2447

2548
<div
2649
className="flex flex-1 w-full h-full overflow-hidden"
2750
style={{
2851
maxHeight: '100vh',
52+
maxWidth: '100vw',
2953
}}
3054
>
3155
<motion.div

apps/agent-tars/src/renderer/src/components/AgentFlowMessage/events/ChatText.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useAtom } from 'jotai';
77
import { canvasStateManager } from '@renderer/state/canvas';
88
import { CanvasType } from '@renderer/type/canvas';
99
import { ipcClient } from '@renderer/api';
10+
import { isReportHtmlMode } from '@renderer/constants';
1011

1112
interface AttachmentItemProps {
1213
path: string;
@@ -50,11 +51,21 @@ export function ChatText({ event }: { event: EventItem }) {
5051
const [, updateCanvasState] = useAtom(canvasStateManager.updateState);
5152

5253
const handleAttachmentClick = async (filePath: string) => {
53-
const content = await ipcClient.getFileContent({
54-
filePath,
55-
});
54+
let content: string | null = null;
55+
if (isReportHtmlMode) {
56+
const artifacts = window.__OMEGA_REPORT_DATA__?.artifacts || {};
57+
const fileName = filePath.split('/').pop()!;
58+
content = artifacts[fileName].content || '';
59+
} else {
60+
content = await ipcClient.getFileContent({
61+
filePath,
62+
});
63+
}
64+
65+
if (!content) {
66+
return;
67+
}
5668

57-
console.log('content', content);
5869
updateCanvasState({
5970
isVisible: true,
6071
dataSource: {

apps/agent-tars/src/renderer/src/components/CanvasPanel/EventPlayer/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,12 @@ export function EventPlayer() {
154154
};
155155

156156
return (
157-
<div className="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg shadow-xl">
157+
<div
158+
className="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg shadow-xl"
159+
style={{
160+
maxHeight: '100vh',
161+
}}
162+
>
158163
{/* Header */}
159164
<div className="flex-shrink-0 flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-800">
160165
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">

apps/agent-tars/src/renderer/src/components/ChatUI/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ import { DEFAULT_APP_ID } from '../LeftSidebar';
2323

2424
declare global {
2525
interface Window {
26-
__OMEGA_REPORT_DATA__?: MessageItem[];
26+
__OMEGA_REPORT_DATA__?: {
27+
messages: MessageItem[];
28+
artifacts: {
29+
[key: string]: {
30+
content: string;
31+
};
32+
};
33+
};
2734
}
2835
}
2936

@@ -69,7 +76,8 @@ export function OpenAgentChatUI() {
6976

7077
useEffect(() => {
7178
async function init() {
72-
const messages = window.__OMEGA_REPORT_DATA__ ?? (await initMessages());
79+
const messages =
80+
window.__OMEGA_REPORT_DATA__?.messages ?? (await initMessages());
7381
setMessages(messages || []);
7482
const events = extractHistoryEvents(messages as unknown as MessageItem[]);
7583
setEvents(events);

apps/agent-tars/src/renderer/src/components/LeftSidebar/TopBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function TopBar({
1919
}: TopBarProps) {
2020
return (
2121
<div className={`${styles.topbar} ${isCollapsed ? styles.collapsed : ''}`}>
22-
{!isCollapsed && <span className={styles.title}>Omega</span>}
22+
{!isCollapsed && <span className={styles.title}>Agent Tars</span>}
2323
<div
2424
className={`${styles.controls} ${isCollapsed ? styles.controlsCollapsed : ''}`}
2525
>

apps/agent-tars/src/renderer/src/hooks/useAgentFlow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function useAgentFlow() {
5858
const result = await ipcClient.askLLMText({
5959
messages: [
6060
Message.systemMessage(
61-
`You are conversation summary expert.Please give a title for the coversation topic, the topic should be no more than 20 words.You can only output the topic content, don't output any other words.Use the same with as the language of the user input.`,
61+
`You are conversation summary expert.Please give a title for the coversation topic, the topic should be no more than 20 words.You can only output the topic content, don't output any other words.Use the same with as the language of the user input.The language should be the same as the user input.`,
6262
),
6363
Message.userMessage(
6464
`user input: ${userMessageContent}, please give me the topic title.`,

0 commit comments

Comments
 (0)