Skip to content

feat: support artifact in replay process #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions apps/agent-tars/src/main/ipcRoutes/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import fs, { readFile } from 'fs-extra';
import { shell } from 'electron';
import fetch from 'node-fetch';
import FormData from 'form-data';
import { normalizeMessages } from '@main/utils/normalizeOmegaData';
import {
normalizeMessages,
parseArtifacts,
} from '@main/utils/normalizeOmegaData';

export interface MCPTool {
id: string;
Expand Down Expand Up @@ -136,10 +139,14 @@ export const actionRoute = t.router({
path.join(__dirname, '../reporter/index.html'),
'utf-8',
);
const artifacts = await parseArtifacts(messages);
const reportContent = reportHtmlTemplate.replace(
' <!-- DATA -->',
'<script>window.__OMEGA_REPORT_DATA__ = ' +
JSON.stringify(messages) +
JSON.stringify({
messages,
artifacts,
}) +
';</script>',
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export class AnthropicProvider extends BaseProvider {
super(config);

// Use environment variables or defaults
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
const baseURL = config.baseURL || process.env.ANTHROPIC_API_BASE_URL;
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY || '';
const baseURL = config.baseURL || process.env.ANTHROPIC_API_BASE_URL || '';

if (!apiKey) {
throw new Error(
Expand Down
59 changes: 56 additions & 3 deletions apps/agent-tars/src/main/utils/normalizeOmegaData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { readFile } from 'fs-extra';
import path from 'path';

interface ImageItem {
type: 'image';
Expand All @@ -20,9 +21,12 @@ interface OmegaAgentMessage {
};
}

export async function normalizeMessages(
messages: Array<OmegaAgentMessage | any>,
) {
function isImage(filePath: string): boolean {
const ext = path.extname(filePath).toLowerCase();
return ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'].includes(ext);
}

export async function normalizeMessages(messages: Array<OmegaAgentMessage>) {
const normalizedMessages = await Promise.all(
messages.map(async (item) => {
if (item.type !== 'omega-agent') {
Expand Down Expand Up @@ -89,3 +93,52 @@ export async function normalizeMessages(

return normalizedMessages;
}

export async function parseArtifacts(messages: Array<OmegaAgentMessage>) {
let artifacts: {
[key: string]: {
content: string;
};
} = {};

await Promise.all(
messages.map(async (item) => {
if (item.type !== 'omega-agent') {
return;
}

await Promise.all(
item.content.events.map(async (event) => {
if (event.type === 'chat-text') {
const { attachments = [] } = event.content;
await Promise.all(
attachments.map(async (attachment) => {
const artifactPath = attachment.path;
const fileName = path.basename(artifactPath);

try {
if (isImage(artifactPath)) {
const base64Content = await readFile(
artifactPath,
'base64',
);
artifacts[fileName] = {
content: `data:image/${path.extname(artifactPath).slice(1)};base64,${base64Content}`,
};
} else {
const content = await readFile(artifactPath, 'utf-8');
artifacts[fileName] = { content };
}
} catch (error) {
console.error(`Failed to read file: ${artifactPath}`, error);
}
}),
);
}
}),
);
}),
);

return artifacts;
}
2 changes: 1 addition & 1 deletion apps/agent-tars/src/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
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:"
/>
</head>
<!-- DATA -->
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- DATA -->
</body>
</html>
2 changes: 1 addition & 1 deletion apps/agent-tars/src/renderer/src/agent/Greeter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class Greeter {
},
});
});
} catch (error) {
} catch (error: any) {
console.log(error);
throw error;
}
Expand Down
36 changes: 30 additions & 6 deletions apps/agent-tars/src/renderer/src/components/AgentApp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,45 @@ import { useFileSystemSettings } from '@renderer/hooks/useFileSystemSettings';

export function AgentApp() {
const [showCanvas] = useAtom(showCanvasAtom);
// Initialize file system settings

useFileSystemSettings();

if (isReportHtmlMode) {
return (
<div className="w-full h-full flex">
<div className="flex flex-1 w-full h-full overflow-hidden">
<div
className="flex-shrink-0"
style={{ width: showCanvas ? '45%' : '100%' }}
>
<OpenAgentChatUI />
</div>
{showCanvas && (
<div
className="flex-shrink-0 bg-background border-l border-divider"
style={{ width: '55%' }}
>
<CanvasPanel />
</div>
)}
</div>
<Toaster position="top-center" />
<FilePermissionHandler />
</div>
);
}

return (
<div className="w-full h-full flex">
{!isReportHtmlMode ? (
<div>
<LeftSidebar />
</div>
) : null}
<div>
<LeftSidebar />
</div>

<div
className="flex flex-1 w-full h-full overflow-hidden"
style={{
maxHeight: '100vh',
maxWidth: '100vw',
}}
>
<motion.div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useAtom } from 'jotai';
import { canvasStateManager } from '@renderer/state/canvas';
import { CanvasType } from '@renderer/type/canvas';
import { ipcClient } from '@renderer/api';
import { isReportHtmlMode } from '@renderer/constants';

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

const handleAttachmentClick = async (filePath: string) => {
const content = await ipcClient.getFileContent({
filePath,
});
let content: string | null = null;
if (isReportHtmlMode) {
const artifacts = window.__OMEGA_REPORT_DATA__?.artifacts || {};
const fileName = filePath.split('/').pop()!;
content = artifacts[fileName].content || '';
} else {
content = await ipcClient.getFileContent({
filePath,
});
}

if (!content) {
return;
}

console.log('content', content);
updateCanvasState({
isVisible: true,
dataSource: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ export function EventPlayer() {
};

return (
<div className="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg shadow-xl">
<div
className="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg shadow-xl"
style={{
maxHeight: '100vh',
}}
>
{/* Header */}
<div className="flex-shrink-0 flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-800">
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
Expand Down
12 changes: 10 additions & 2 deletions apps/agent-tars/src/renderer/src/components/ChatUI/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ import { DEFAULT_APP_ID } from '../LeftSidebar';

declare global {
interface Window {
__OMEGA_REPORT_DATA__?: MessageItem[];
__OMEGA_REPORT_DATA__?: {
messages: MessageItem[];
artifacts: {
[key: string]: {
content: string;
};
};
};
}
}

Expand Down Expand Up @@ -69,7 +76,8 @@ export function OpenAgentChatUI() {

useEffect(() => {
async function init() {
const messages = window.__OMEGA_REPORT_DATA__ ?? (await initMessages());
const messages =
window.__OMEGA_REPORT_DATA__?.messages ?? (await initMessages());
setMessages(messages || []);
const events = extractHistoryEvents(messages as unknown as MessageItem[]);
setEvents(events);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function TopBar({
}: TopBarProps) {
return (
<div className={`${styles.topbar} ${isCollapsed ? styles.collapsed : ''}`}>
{!isCollapsed && <span className={styles.title}>Omega</span>}
{!isCollapsed && <span className={styles.title}>Agent Tars</span>}
<div
className={`${styles.controls} ${isCollapsed ? styles.controlsCollapsed : ''}`}
>
Expand Down
2 changes: 1 addition & 1 deletion apps/agent-tars/src/renderer/src/hooks/useAgentFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function useAgentFlow() {
const result = await ipcClient.askLLMText({
messages: [
Message.systemMessage(
`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.`,
`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.`,
),
Message.userMessage(
`user input: ${userMessageContent}, please give me the topic title.`,
Expand Down
Loading