diff --git a/src/cli/commands/invoke/action.ts b/src/cli/commands/invoke/action.ts index 449738fc..4c667338 100644 --- a/src/cli/commands/invoke/action.ts +++ b/src/cli/commands/invoke/action.ts @@ -118,12 +118,13 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption agentName: agentSpec.name, runtimeArn: agentState.runtimeArn, region: targetConfig.region, + sessionId: options.sessionId, }); const command = options.prompt; if (!command) { return { success: false, error: '--exec requires a command (prompt)' }; } - logger.logPrompt(command, undefined, options.userId); + logger.logPrompt(command, options.sessionId, options.userId); try { const result = await executeBashCommand({ @@ -324,9 +325,10 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption agentName: agentSpec.name, runtimeArn: agentState.runtimeArn, region: targetConfig.region, + sessionId: options.sessionId, }); - logger.logPrompt(options.prompt, undefined, options.userId); + logger.logPrompt(options.prompt, options.sessionId, options.userId); if (options.stream) { // Streaming mode diff --git a/src/cli/logging/__tests__/invoke-logger-session-id.test.ts b/src/cli/logging/__tests__/invoke-logger-session-id.test.ts new file mode 100644 index 00000000..30452fb6 --- /dev/null +++ b/src/cli/logging/__tests__/invoke-logger-session-id.test.ts @@ -0,0 +1,96 @@ +import { InvokeLogger } from '../invoke-logger.js'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('../../../lib', async importOriginal => { + const actual = await importOriginal(); + return { + ...actual, + findConfigRoot: () => tempDir, + }; +}); + +let tempDir: string; + +beforeEach(() => { + tempDir = mkdtempSync(path.join(tmpdir(), 'invoke-logger-test-')); +}); + +afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }); +}); + +function readLog(logger: InvokeLogger): string { + return readFileSync(logger.logFilePath, 'utf-8'); +} + +describe('InvokeLogger session ID', () => { + it('writes session ID in header when provided via constructor', () => { + const logger = new InvokeLogger({ + agentName: 'testAgent', + runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456:runtime/test', + region: 'us-east-1', + sessionId: 'my-session-123', + }); + + const content = readLog(logger); + expect(content).toContain('Session ID: my-session-123'); + expect(content).not.toContain('Session ID: none'); + }); + + it('writes "none" when session ID is not provided', () => { + const logger = new InvokeLogger({ + agentName: 'testAgent', + runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456:runtime/test', + region: 'us-east-1', + }); + + const content = readLog(logger); + expect(content).toContain('Session ID: none'); + }); + + it('includes session ID in logPrompt output when passed as argument', () => { + const logger = new InvokeLogger({ + agentName: 'testAgent', + runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456:runtime/test', + region: 'us-east-1', + sessionId: 'my-session-456', + }); + + logger.logPrompt('hello world', 'my-session-456', 'user-1'); + + const content = readLog(logger); + expect(content).toContain('Session: my-session-456'); + expect(content).toContain('"sessionId": "my-session-456"'); + }); + + it('logPrompt falls back to constructor sessionId when argument is undefined', () => { + const logger = new InvokeLogger({ + agentName: 'testAgent', + runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456:runtime/test', + region: 'us-east-1', + sessionId: 'constructor-session', + }); + + logger.logPrompt('hello world', undefined, 'user-1'); + + const content = readLog(logger); + expect(content).toContain('Session: constructor-session'); + expect(content).toContain('"sessionId": "constructor-session"'); + }); + + it('logPrompt shows "none" when no session ID anywhere', () => { + const logger = new InvokeLogger({ + agentName: 'testAgent', + runtimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456:runtime/test', + region: 'us-east-1', + }); + + logger.logPrompt('hello world'); + + const content = readLog(logger); + expect(content).toContain('Session: none'); + }); +});