Browse Source

Merge pull request #719 from mhenke/fix/485-interview-session-rename

Rename the session when /interview starts
Alvin 1 month ago
parent
commit
15a4845b8c
3 changed files with 64 additions and 0 deletions
  1. 50 0
      src/interview/interview.test.ts
  2. 1 0
      src/interview/manager.test.ts
  3. 13 0
      src/interview/service.ts

+ 50 - 0
src/interview/interview.test.ts

@@ -40,6 +40,7 @@ function createMockContext(overrides?: {
           }
           return {};
         }),
+        update: mock(async () => ({})),
       },
     },
     directory: overrides?.directory ?? '/test/directory',
@@ -173,6 +174,55 @@ describe('interview service', () => {
       await fs.rm(tempDir, { recursive: true, force: true });
     });
 
+    test('renames session with interview title on creation', async () => {
+      const tempDir = await fs.mkdtemp('/tmp/interview-test-');
+      const ctx = createMockContext({ directory: tempDir });
+      const service = createInterviewService(ctx);
+      service.setBaseUrlResolver(async () => 'http://localhost:9999');
+      const output = { parts: [] as Array<{ type: string; text?: string }> };
+
+      await service.handleCommandExecuteBefore(
+        {
+          command: 'interview',
+          sessionID: 'session-rename',
+          arguments: 'build a task manager',
+        },
+        output,
+      );
+
+      expect(ctx.client.session.update).toHaveBeenCalledTimes(1);
+      expect(ctx.client.session.update.mock.calls[0][0]).toEqual({
+        path: { id: 'session-rename' },
+        body: { title: 'Interview: build a task manager' },
+      });
+
+      await fs.rm(tempDir, { recursive: true, force: true });
+    });
+
+    test('truncates session title to 50 chars with ellipsis', async () => {
+      const tempDir = await fs.mkdtemp('/tmp/interview-test-');
+      const ctx = createMockContext({ directory: tempDir });
+      const service = createInterviewService(ctx);
+      service.setBaseUrlResolver(async () => 'http://localhost:9999');
+      const output = { parts: [] as Array<{ type: string; text?: string }> };
+
+      const longIdea = 'a'.repeat(60);
+      await service.handleCommandExecuteBefore(
+        {
+          command: 'interview',
+          sessionID: 'session-truncate',
+          arguments: longIdea,
+        },
+        output,
+      );
+
+      const title = ctx.client.session.update.mock.calls[0][0].body.title;
+      expect(title.length).toBe(50);
+      expect(title.endsWith('…')).toBe(true);
+
+      await fs.rm(tempDir, { recursive: true, force: true });
+    });
+
     test('creates markdown file with slug-only filename (no timestamp prefix)', async () => {
       const tempDir = await fs.mkdtemp('/tmp/interview-test-');
       const ctx = createMockContext({ directory: tempDir });

+ 1 - 0
src/interview/manager.test.ts

@@ -48,6 +48,7 @@ function createMockContext(overrides?: {
           }
           return {};
         }),
+        update: mock(async () => ({})),
       },
     },
     directory: overrides?.directory ?? '/test/directory',

+ 13 - 0
src/interview/service.ts

@@ -686,6 +686,19 @@ export function createInterviewService(
     output.parts.push(
       createInternalAgentTextPart(buildKickoffPrompt(idea, maxQuestions)),
     );
+
+    // best-effort: rename the session so it's identifiable in the session list.
+    // never block interview creation if the rename fails.
+    let sessionTitle = `Interview: ${idea}`;
+    if (sessionTitle.length > 50) {
+      sessionTitle = `${sessionTitle.slice(0, 49)}…`;
+    }
+    ctx.client.session
+      .update?.({
+        path: { id: input.sessionID },
+        body: { title: sessionTitle },
+      })
+      ?.catch(() => {});
   }
 
   async function handleEvent(input: {