diff --git a/apps/x/packages/core/src/config/user_config.ts b/apps/x/packages/core/src/config/user_config.ts new file mode 100644 index 00000000..75034946 --- /dev/null +++ b/apps/x/packages/core/src/config/user_config.ts @@ -0,0 +1,44 @@ +import fs from 'fs'; +import path from 'path'; +import { z } from 'zod'; +import { WorkDir } from './config.js'; + +const USER_CONFIG_PATH = path.join(WorkDir, 'config', 'user.json'); + +export const UserConfig = z.object({ + name: z.string().optional(), + email: z.string().email(), + domain: z.string().optional(), +}); + +export type UserConfig = z.infer; + +export function loadUserConfig(): UserConfig | null { + try { + if (fs.existsSync(USER_CONFIG_PATH)) { + const content = fs.readFileSync(USER_CONFIG_PATH, 'utf-8'); + const parsed = JSON.parse(content); + return UserConfig.parse(parsed); + } + } catch (error) { + console.error('[UserConfig] Error loading user config:', error); + } + return null; +} + +export function saveUserConfig(config: UserConfig): void { + const dir = path.dirname(USER_CONFIG_PATH); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + const validated = UserConfig.parse(config); + fs.writeFileSync(USER_CONFIG_PATH, JSON.stringify(validated, null, 2)); +} + +export function updateUserEmail(email: string): void { + const existing = loadUserConfig(); + const config = existing + ? { ...existing, email } + : { email }; + saveUserConfig(config); +} diff --git a/apps/x/packages/core/src/knowledge/agent_notes.ts b/apps/x/packages/core/src/knowledge/agent_notes.ts index b9f10f38..433423ac 100644 --- a/apps/x/packages/core/src/knowledge/agent_notes.ts +++ b/apps/x/packages/core/src/knowledge/agent_notes.ts @@ -1,10 +1,12 @@ import fs from 'fs'; import path from 'path'; +import { google } from 'googleapis'; import { WorkDir } from '../config/config.js'; import { createRun, createMessage } from '../runs/runs.js'; import { bus } from '../runs/bus.js'; import { serviceLogger } from '../services/service_logger.js'; -import { loadUserConfig } from '../pre_built/config.js'; +import { loadUserConfig, updateUserEmail } from '../config/user_config.js'; +import { GoogleClientFactory } from './google-client-factory.js'; import { loadAgentNotesState, saveAgentNotesState, @@ -199,28 +201,52 @@ async function waitForRunCompletion(runId: string): Promise { }); } +// --- User email resolution --- + +async function ensureUserEmail(): Promise { + const existing = loadUserConfig(); + if (existing?.email) { + return existing.email; + } + + // Try to get email from Gmail profile + try { + const auth = await GoogleClientFactory.getClient(); + if (auth) { + const gmail = google.gmail({ version: 'v1', auth }); + const profile = await gmail.users.getProfile({ userId: 'me' }); + if (profile.data.emailAddress) { + updateUserEmail(profile.data.emailAddress); + console.log(`[AgentNotes] Auto-populated user email: ${profile.data.emailAddress}`); + return profile.data.emailAddress; + } + } + } catch (error) { + console.log('[AgentNotes] Could not fetch Gmail profile for user email:', error instanceof Error ? error.message : error); + } + + return null; +} + // --- Main processing --- async function processAgentNotes(): Promise { - const userConfig = loadUserConfig(); - if (!userConfig) { - console.log('[AgentNotes] No user config found, skipping'); - return; - } - ensureAgentNotesDir(); const state = loadAgentNotesState(); + const userEmail = await ensureUserEmail(); // Collect all source material const messageParts: string[] = []; - // 1. Emails - const emailPaths = findUserSentEmails(state, userConfig.email, EMAIL_BATCH_SIZE); + // 1. Emails (only if we have user email) + const emailPaths = userEmail + ? findUserSentEmails(state, userEmail, EMAIL_BATCH_SIZE) + : []; if (emailPaths.length > 0) { - messageParts.push(`## Emails sent by ${userConfig.name}\n`); + messageParts.push(`## Emails sent by the user\n`); for (const p of emailPaths) { const content = fs.readFileSync(p, 'utf-8'); - const userParts = extractUserPartsFromEmail(content, userConfig.email); + const userParts = extractUserPartsFromEmail(content, userEmail!); if (userParts) { messageParts.push(`---\n${userParts}\n---\n`); }