chore(telemetry): track conversation undo, shell mode, and effort changes (#1271)

* chore(telemetry): track conversation undo, shell mode, and effort changes

- conversation_undo: fires when an undo reverts history (double-Esc selector, /undo, /undo N)
- shell_command: fires when a ! shell command runs in the TUI
- thinking_toggle: now fires on any effort change (not just on/off flips) and carries { enabled, effort, from }; align the no-session TUI path to the same payload

* chore(telemetry): track conversation_undo in core undoHistory

Tracking it in the TUI only covered the TUI; web/acp/REST undos reach
core.rpc.undoHistory directly and were missed. Emit the event from the
agent undoHistory RPC after the undo succeeds so every host is covered,
and drop the now-redundant TUI track.

Addresses review feedback on #1271.
This commit is contained in:
liruifengv 2026-07-01 20:04:31 +08:00 committed by GitHub
parent c070fbedde
commit 3cb7936cf5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 36 additions and 7 deletions

View file

@ -422,7 +422,11 @@ async function performModelSwitch(
host.track('model_switch', { model: alias });
}
if (effort !== prevEffort) {
host.track('thinking_toggle', { effort });
host.track('thinking_toggle', {
enabled: effort !== 'off',
effort,
from: prevEffort,
});
}
}

View file

@ -955,6 +955,8 @@ export class KimiTUI {
this.setAppState({ streamingPhase: 'shell' });
this.state.ui.requestRender();
this.track('shell_command');
void session.runShellCommand(command, { commandId }).then(
({ stdout, stderr, isError, backgrounded }) => {
this.finishShellOutput(commandId, stdout, stderr, isError, backgrounded);

View file

@ -1766,13 +1766,15 @@ command = "vim"
it('echoes a bash command with a $ prompt in the transcript', async () => {
const runShellCommand = vi.fn(async () => ({ stdout: '', stderr: '', isError: false }));
const session = makeSession({ runShellCommand });
const { driver } = await makeDriver(session);
const { driver, harness } = await makeDriver(session);
driver.state.appState.inputMode = 'bash';
driver.state.editor.inputMode = 'bash';
driver.handleUserInput('ls');
await Promise.resolve();
expect(harness.track).toHaveBeenCalledWith('shell_command', undefined);
const transcript = stripSgr(driver.state.transcriptContainer.render(120).join('\n'));
expect(transcript).toContain('$ ls');
expect(transcript).not.toContain('! ls');