Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const createConfig = (overrides: Record<string, unknown> = {}): Config => {
return {
getContentGeneratorConfig: () => configContent,
getAuthType: () => configContent.authType as AuthType | undefined,
getWorkingDir: () => process.cwd(),
} as Config;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ export class LoggingContentGenerator implements ContentGenerator {
// Extract fields needed for initialization from passed config
// (config.getContentGeneratorConfig() may not be available yet during refreshAuth)
if (generatorConfig.enableOpenAILogging) {
this.openaiLogger = new OpenAILogger(generatorConfig.openAILoggingDir);
this.openaiLogger = new OpenAILogger(
generatorConfig.openAILoggingDir,
config.getWorkingDir(),
);
this.schemaCompliance = generatorConfig.schemaCompliance;
}
}
Expand Down
82 changes: 82 additions & 0 deletions packages/core/src/utils/openaiLogger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,86 @@ describe('OpenAILogger', () => {
expect(logPath).toContain(specialPath);
});
});

describe('cwd parameter', () => {
it('should use provided cwd for default log directory instead of process.cwd()', async () => {
const customCwd = path.join(testTempDir, 'project-root');
await fs.mkdir(customCwd, { recursive: true });
const logger = new OpenAILogger(undefined, customCwd);
await logger.initialize();

const request = { test: 'request' };
const response = { test: 'response' };

const logPath = await logger.logInteraction(request, response);
const expectedDir = path.join(customCwd, 'logs', 'openai');
createdDirs.push(expectedDir);

expect(logPath).toContain(expectedDir);
});

it('should resolve relative customLogDir against provided cwd', async () => {
const customCwd = path.join(testTempDir, 'project-root-2');
await fs.mkdir(customCwd, { recursive: true });
const relativeDir = 'my-logs';
const logger = new OpenAILogger(relativeDir, customCwd);
await logger.initialize();

const request = { test: 'request' };
const response = { test: 'response' };

const logPath = await logger.logInteraction(request, response);
const expectedDir = path.resolve(customCwd, relativeDir);
createdDirs.push(expectedDir);

expect(logPath).toContain(expectedDir);
});

it('should not use cwd when customLogDir is an absolute path', async () => {
const customCwd = path.join(testTempDir, 'project-root-3');
const absoluteLogDir = path.join(testTempDir, 'absolute-logs');
const logger = new OpenAILogger(absoluteLogDir, customCwd);
await logger.initialize();

const request = { test: 'request' };
const response = { test: 'response' };

const logPath = await logger.logInteraction(request, response);
createdDirs.push(absoluteLogDir);

expect(logPath).toContain(absoluteLogDir);
expect(logPath).not.toContain(customCwd);
});

it('should not use cwd when customLogDir starts with ~', async () => {
const customCwd = path.join(testTempDir, 'project-root-4');
const logger = new OpenAILogger('~/test-openai-logs', customCwd);
await logger.initialize();

const request = { test: 'request' };
const response = { test: 'response' };

const logPath = await logger.logInteraction(request, response);
const expectedDir = path.join(os.homedir(), 'test-openai-logs');
createdDirs.push(expectedDir);

expect(logPath).toContain(expectedDir);
expect(logPath).not.toContain(customCwd);
});

it('should fall back to process.cwd() when cwd is not provided', async () => {
const relativeDir = 'test-relative-logs';
const logger = new OpenAILogger(relativeDir);
await logger.initialize();

const request = { test: 'request' };
const response = { test: 'response' };

const logPath = await logger.logInteraction(request, response);
const expectedDir = path.resolve(process.cwd(), relativeDir);
createdDirs.push(expectedDir);

expect(logPath).toContain(expectedDir);
});
});
});
12 changes: 8 additions & 4 deletions packages/core/src/utils/openaiLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,25 @@ export class OpenAILogger {
/**
* Creates a new OpenAI logger
* @param customLogDir Optional custom log directory path (supports relative paths, absolute paths, and ~ expansion)
* @param cwd Optional working directory for resolving relative paths. Defaults to process.cwd().
* In ACP mode, process.cwd() may be '/' (filesystem root), so callers should
* pass the project working directory from Config.getWorkingDir().
*/
constructor(customLogDir?: string) {
constructor(customLogDir?: string, cwd?: string) {
const baseCwd = cwd || process.cwd();
if (customLogDir) {
// Resolve relative paths to absolute paths
// Handle ~ expansion
let resolvedPath = customLogDir;
if (customLogDir === '~' || customLogDir.startsWith('~/')) {
resolvedPath = path.join(os.homedir(), customLogDir.slice(1));
} else if (!path.isAbsolute(customLogDir)) {
// If it's a relative path, resolve it relative to current working directory
resolvedPath = path.resolve(process.cwd(), customLogDir);
// If it's a relative path, resolve it relative to provided working directory
resolvedPath = path.resolve(baseCwd, customLogDir);
}
this.logDir = path.normalize(resolvedPath);
} else {
this.logDir = path.join(process.cwd(), 'logs', 'openai');
this.logDir = path.join(baseCwd, 'logs', 'openai');
}
}

Expand Down
Loading