Skip to content

Commit 86e5980

Browse files
committed
feat(agent-tars): support "view logs" for trouble shooting
1 parent ec61134 commit 86e5980

File tree

18 files changed

+479
-36
lines changed

18 files changed

+479
-36
lines changed

apps/agent-tars/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"openai": "^4.86.2",
5555
"dotenv": "16.4.7",
5656
"@agent-infra/shared": "workspace:*",
57+
"@agent-infra/logger": "workspace:*",
5758
"@agent-infra/mcp-client": "workspace:*",
5859
"@agent-infra/search": "workspace:*",
5960
"ws": "8.18.1",

apps/agent-tars/src/main/customTools/search.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ import {
66
import { MCPToolResult } from '@main/type';
77
import { tavily as tavilyCore } from '@tavily/core';
88
import { SettingStore } from '@main/store/setting';
9+
import { logger } from '@main/utils/logger';
10+
import { maskSensitiveData } from '@main/utils/maskSensitiveData';
911

1012
export const tavily = tavilyCore;
1113

1214
const searchByTavily = async (options: { count: number; query: string }) => {
1315
const currentSearchConfig = SettingStore.get('search');
16+
const apiKey = process.env.TAVILY_API_KEY || currentSearchConfig?.apiKey;
1417
const client = tavily({
15-
apiKey: process.env.TAVILY_API_KEY || currentSearchConfig?.apiKey,
18+
apiKey,
1619
});
1720
const searchOptions = {
1821
maxResults: options.count,
@@ -33,6 +36,11 @@ export async function search(toolCall: ToolCall): Promise<MCPToolResult> {
3336
const args = JSON.parse(toolCall.function.arguments);
3437

3538
try {
39+
logger.info(
40+
'Search query:',
41+
maskSensitiveData({ query: args.query, count: args.count }),
42+
);
43+
3644
if (!currentSearchConfig) {
3745
const client = new SearchClient({
3846
provider: SearchProviderEnum.DuckduckgoSearch,
@@ -105,7 +113,7 @@ export async function search(toolCall: ToolCall): Promise<MCPToolResult> {
105113
},
106114
];
107115
} catch (e) {
108-
console.error('Search error:', e);
116+
logger.error('Search error:', e);
109117
return [
110118
{
111119
isError: true,

apps/agent-tars/src/main/index.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { updateElectronApp, UpdateSourceType } from 'update-electron-app';
55
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
66
import { ipcRoutes } from './ipcRoutes';
77
import icon from '../../resources/icon.png?asset';
8+
import MenuBuilder from './menu';
9+
import { logger } from './utils/logger';
810

911
class AppUpdater {
1012
constructor() {
@@ -65,6 +67,7 @@ function createWindow(): void {
6567

6668
mainWindow.on('ready-to-show', () => {
6769
mainWindow.show();
70+
logger.info('Application window is ready and shown');
6871
});
6972

7073
mainWindow.webContents.setWindowOpenHandler((details) => {
@@ -79,16 +82,21 @@ function createWindow(): void {
7982
} else {
8083
mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
8184
}
85+
// Set up the application menu
86+
const menuBuilder = new MenuBuilder(mainWindow);
87+
menuBuilder.buildMenu();
8288
}
8389

8490
const initializeApp = async () => {
91+
logger.info('Initializing application');
92+
8593
if (process.platform === 'darwin') {
8694
app.setAccessibilitySupportEnabled(true);
8795
const { ensurePermissions } = await import('@main/utils/systemPermissions');
8896

8997
const ensureScreenCapturePermission = ensurePermissions();
90-
console.info(
91-
'ensureScreenCapturePermission',
98+
logger.info(
99+
'Screen capture permission status:',
92100
ensureScreenCapturePermission,
93101
);
94102
}
@@ -98,6 +106,8 @@ const initializeApp = async () => {
98106
// initialization and is ready to create browser windows.
99107
// Some APIs can only be used after this event occurs.
100108
app.whenReady().then(async () => {
109+
logger.info('Application is ready');
110+
101111
// Set app user model id for windows
102112
electronApp.setAppUserModelId('com.electron');
103113

@@ -113,7 +123,10 @@ app.whenReady().then(async () => {
113123
await initializeApp();
114124

115125
// IPC test
116-
ipcMain.on('ping', () => console.log('pong'));
126+
ipcMain.on('ping', () => {
127+
logger.info('Received ping event');
128+
logger.info('pong');
129+
});
117130
registerIpcMain(ipcRoutes);
118131

119132
createWindow();
@@ -129,6 +142,7 @@ app.whenReady().then(async () => {
129142
// for applications and their menu bar to stay active until the user quits
130143
// explicitly with Cmd + Q.
131144
app.on('window-all-closed', () => {
145+
logger.info('All windows closed');
132146
if (process.platform !== 'darwin') {
133147
app.quit();
134148
}

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

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
12
import { MCPServerName, ToolCall } from '@agent-infra/shared';
23
import { executeCustomTool, listCustomTools } from '@main/customTools';
34
import { createMcpClient, getOmegaDir } from '@main/mcp/client';
@@ -15,6 +16,8 @@ import {
1516
normalizeMessages,
1617
parseArtifacts,
1718
} from '@main/utils/normalizeOmegaData';
19+
import { logger } from '@main/utils/logger';
20+
import { extractToolNames } from '@main/utils/extractToolNames';
1821

1922
export interface MCPTool {
2023
id: string;
@@ -44,7 +47,7 @@ export const actionRoute = t.router({
4447
listTools: t.procedure.handle(async () => {
4548
const mcpClient = await createMcpClient();
4649
const tools = mcpToolsToAzureTools(await mcpClient.listTools());
47-
console.log('toolstools', tools);
50+
logger.info('[actionRoute.listTools] tools', extractToolNames(tools));
4851
const customTools = listCustomTools();
4952
return [
5053
...tools.map((tool) => tool.function),
@@ -74,7 +77,11 @@ export const actionRoute = t.router({
7477
for (const toolCall of input.toolCalls) {
7578
const mcpTool = toolUseToMcpTool(tools, toolCall);
7679
if (mcpTool) {
77-
console.log('i will execute tool', mcpTool.name, mcpTool.inputSchema);
80+
logger.info(
81+
'[actionRoute.executeTool] i will execute mcp tool',
82+
mcpTool.name,
83+
mcpTool.inputSchema || {},
84+
);
7885
try {
7986
const result = await mcpClient.callTool({
8087
client: mcpTool.serverName as MCPServerName,
@@ -83,16 +90,26 @@ export const actionRoute = t.router({
8390
});
8491
results.push(result);
8592
} catch (e) {
86-
console.error('execute tool error', mcpTool, e);
93+
logger.error(
94+
'[actionRoute.executeTool] execute tool error',
95+
mcpTool.name,
96+
e,
97+
);
8798
results.push({
8899
isError: true,
89100
content: [JSON.stringify(e)],
90101
});
91102
}
92103
} else {
93-
console.log('executeCustomTool_toolCall', toolCall);
104+
logger.info(
105+
'[actionRoute.executeTool] executeCustomTool_toolCall',
106+
toolCall,
107+
);
94108
const result = await executeCustomTool(toolCall);
95-
console.log('executeCustomTool_result', result);
109+
logger.info(
110+
'[actionRoute.executeTool] executeCustomTool_result',
111+
result ? 'success' : 'no result',
112+
);
96113
if (result) {
97114
results.push(...result);
98115
}
@@ -102,6 +119,7 @@ export const actionRoute = t.router({
102119
}),
103120

104121
saveBrowserSnapshot: t.procedure.input<void>().handle(async () => {
122+
logger.info('[actionRoute.saveBrowserSnapshot] start');
105123
const mcpClient = await createMcpClient();
106124
try {
107125
const result = await mcpClient.callTool({
@@ -128,7 +146,10 @@ export const actionRoute = t.router({
128146
await fs.writeFile(filepath, imageBuffer);
129147
return { filepath };
130148
} catch (e) {
131-
console.error('Failed to save screenshot:', e);
149+
logger.error(
150+
'[actionRoute.saveBrowserSnapshot] Failed to save screenshot:',
151+
e,
152+
);
132153
throw e;
133154
}
134155
}),
@@ -183,7 +204,7 @@ export const actionRoute = t.router({
183204
await fs.remove(tempPath);
184205

185206
if (!res.ok) {
186-
console.error('Upload failed:', await res.text());
207+
logger.error('Upload failed:', await res.text());
187208
throw new Error('文件上传失败');
188209
}
189210

@@ -195,7 +216,7 @@ export const actionRoute = t.router({
195216
await shell.openExternal(data.url);
196217
return data.url;
197218
} catch (error) {
198-
console.error('Upload failed:', error);
219+
logger.error('Upload failed:', error);
199220
throw error;
200221
}
201222
} else {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { initIpc } from '@ui-tars/electron-ipc/main';
2+
import { logger } from '@main/utils/logger';
23

34
const t = initIpc.create();
45

56
export const agentRoute = t.router({
67
runAgent: t.procedure.input<void>().handle(async () => {
7-
console.log('runAgent');
8+
logger.info('runAgent');
89
return 'Hello';
910
}),
1011
});

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { setAllowedDirectories, getAllowedDirectories } from '@main/mcp/client';
33
import path from 'path';
44
import os from 'os';
55
import fs from 'fs-extra';
6+
import { logger } from '@main/utils/logger';
67

78
const t = initIpc.create();
89

@@ -40,15 +41,15 @@ export const fileSystemRoute = t.router({
4041
const content = await fs.readFile(input.filePath, 'utf8');
4142
return content;
4243
} catch (error) {
43-
console.error('Failed to read file:', error);
44+
logger.error('Failed to read file:', error);
4445
return null;
4546
}
4647
}),
4748
getAllowedDirectories: t.procedure.input<void>().handle(async () => {
4849
try {
4950
return await getAllowedDirectories();
5051
} catch (error) {
51-
console.error('Failed to get allowed directories:', error);
52+
logger.error('Failed to get allowed directories:', error);
5253
const omegaDir = path.join(os.homedir(), '.omega');
5354
return [omegaDir];
5455
}

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { BrowserWindow } from 'electron';
1010
import { createLLM, LLMConfig } from '@main/llmProvider';
1111
import { ProviderFactory } from '@main/llmProvider/ProviderFactory';
1212
import { SettingStore } from '@main/store/setting';
13+
import { logger } from '@main/utils/logger';
14+
import { maskSensitiveData } from '@main/utils/maskSensitiveData';
15+
import { extractToolNames } from '@main/utils/extractToolNames';
1316

1417
const t = initIpc.create();
1518

@@ -42,6 +45,7 @@ export const llmRoute = t.router({
4245
requestId: string;
4346
}>()
4447
.handle(async ({ input }) => {
48+
logger.info('[llmRoute.askLLMText] input', input);
4549
const messages = input.messages.map((msg) => new Message(msg));
4650
const llm = createLLM(currentLLMConfigRef.current);
4751
const response = await llm.askLLMText({
@@ -59,11 +63,18 @@ export const llmRoute = t.router({
5963
requestId: string;
6064
}>()
6165
.handle(async ({ input }) => {
66+
logger.info('[llmRoute.askLLMTool] input', input);
6267
const messages = input.messages.map((msg) => new Message(msg));
6368
const llm = createLLM(currentLLMConfigRef.current);
64-
console.log('current llm config', currentLLMConfigRef.current);
65-
console.log('current search config', SettingStore.get('search'));
66-
console.log('input.tools', input.tools);
69+
logger.info(
70+
'[llmRoute.askLLMTool] Current LLM Config',
71+
maskSensitiveData(currentLLMConfigRef.current),
72+
);
73+
logger.info(
74+
'[llmRoute.askLLMTool] Current Search Config',
75+
maskSensitiveData(SettingStore.get('search')),
76+
);
77+
logger.info('[llmRoute.askLLMTool] tools', extractToolNames(input.tools));
6778
const response = await llm.askTool({
6879
messages,
6980
tools: input.tools,
@@ -80,9 +91,13 @@ export const llmRoute = t.router({
8091
requestId: string;
8192
}>()
8293
.handle(async ({ input }) => {
94+
logger.info('[llmRoute.askLLMTextStream] input', input);
8395
const messages = input.messages.map((msg) => new Message(msg));
8496
const { requestId } = input;
85-
console.log('current llm config', currentLLMConfigRef.current);
97+
logger.info(
98+
'[llmRoute.askLLMTextStream] Current LLM Config',
99+
maskSensitiveData(currentLLMConfigRef.current),
100+
);
86101
const llm = createLLM(currentLLMConfigRef.current);
87102

88103
(async () => {
@@ -120,12 +135,13 @@ export const llmRoute = t.router({
120135
updateLLMConfig: t.procedure
121136
.input<ModelSettings>()
122137
.handle(async ({ input }) => {
138+
logger.info('[llmRoute.updateLLMConfig] input', maskSensitiveData(input));
123139
try {
124140
SettingStore.set('model', input);
125141
currentLLMConfigRef.current = getLLMProviderConfig(input);
126142
return true;
127143
} catch (error) {
128-
console.error('Failed to update LLM configuration:', error);
144+
logger.error('Failed to update LLM configuration:', error);
129145
return false;
130146
}
131147
}),
@@ -134,19 +150,20 @@ export const llmRoute = t.router({
134150
try {
135151
return ProviderFactory.getAvailableProviders();
136152
} catch (error) {
137-
console.error('Failed to get available providers:', error);
153+
logger.error('Failed to get available providers:', error);
138154
return [];
139155
}
140156
}),
141157
abortRequest: t.procedure
142158
.input<{ requestId: string }>()
143159
.handle(async ({ input }) => {
160+
logger.info('[llmRoute.abortRequest] input', input);
144161
try {
145162
const llm = createLLM(currentLLMConfigRef.current);
146163
llm.abortRequest(input.requestId);
147164
return true;
148165
} catch (error) {
149-
console.error('Failed to abort request:', error);
166+
logger.error('Failed to abort request:', error);
150167
return false;
151168
}
152169
}),

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { initIpc } from '@ui-tars/electron-ipc/main';
22
import { SearchSettings } from '@agent-infra/shared';
33
import { SettingStore } from '@main/store/setting';
4+
import { logger } from '@main/utils/logger';
5+
import { maskSensitiveData } from '@main/utils/maskSensitiveData';
46

57
const t = initIpc.create();
68

@@ -9,10 +11,17 @@ export const searchRoute = t.router({
911
.input<SearchSettings>()
1012
.handle(async ({ input }) => {
1113
try {
14+
logger.info(
15+
'[searchRoute.updateSearchConfig] Updating search configuration:',
16+
maskSensitiveData(input),
17+
);
1218
SettingStore.set('search', input);
1319
return true;
1420
} catch (error) {
15-
console.error('Failed to update search configuration:', error);
21+
logger.error(
22+
'[searchRoute.updateSearchConfig] Failed to update search configuration:',
23+
error,
24+
);
1625
return false;
1726
}
1827
}),

apps/agent-tars/src/main/llmProvider/ProviderFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { AnthropicProvider } from './providers/AnthropicProvider';
44
import { AzureOpenAIProvider } from './providers/AzureOpenAIProvider';
55
import { GeminiProvider } from './providers/GeminiProvider';
66
import { MistralProvider } from './providers/MistralProvider';
7+
import { logger } from '@main/utils/logger';
78

89
// Define model prefixes that will be used to determine the provider
910
const MODEL_PREFIXES = {
@@ -63,7 +64,7 @@ export class ProviderFactory {
6364
}
6465

6566
// Default to OpenAI if model doesn't match any known prefix
66-
console.warn(
67+
logger.warn(
6768
`Unknown model prefix: ${model}. Defaulting to OpenAI provider.`,
6869
);
6970
return new OpenAIProvider(config);

0 commit comments

Comments
 (0)