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
4 changes: 2 additions & 2 deletions apps/kimi-code/src/cli/sub/server/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { startServer, type RunningServer } from '@moonshot-ai/server';
import chalk from 'chalk';
import { Option, type Command } from 'commander';

import { CLI_SHUTDOWN_TIMEOUT_MS, WEB_UI_MODE } from '#/constant/app';
import { CLI_SHUTDOWN_TIMEOUT_MS } from '#/constant/app';
import { getNativeWebAssetsDir } from '#/native/web-assets';
import { darkColors } from '#/tui/theme/colors';
import { openUrl as defaultOpenUrl } from '#/utils/open-url';
Expand Down Expand Up @@ -346,7 +346,7 @@ async function runServerInProcess(
},
});

track('server_started', { ui_mode: WEB_UI_MODE, daemon: mode.daemon });
track('server_started', { daemon: mode.daemon });

process.once('SIGINT', () => {
void shutdown('SIGINT');
Expand Down
2 changes: 0 additions & 2 deletions apps/kimi-code/src/cli/update/preflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,6 @@ function trackUpdatePrompted(
rolloutTelemetry: RolloutTelemetry,
): void {
trackUpdateEvent(track, 'update_prompted', {
current: currentVersion,
latest: target.version,
current_version: currentVersion,
target_version: target.version,
source,
Expand Down
1 change: 1 addition & 0 deletions apps/kimi-code/src/tui/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ async function handleKimiCodeOAuthLogin(host: SlashCommandHost): Promise<void> {
}
host.track('login', {
provider: DEFAULT_OAUTH_PROVIDER_NAME,
method: 'oauth',
already_logged_in: alreadyLoggedIn,
});
if (alreadyLoggedIn) {
Expand Down
8 changes: 4 additions & 4 deletions apps/kimi-code/test/cli/update/preflight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,8 @@ describe('runUpdatePreflight', () => {
const track = vi.fn();
await runUpdatePreflight('0.4.0', { ...options, track });
expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({
current: '0.4.0',
latest: '0.5.0',
current_version: '0.4.0',
target_version: '0.5.0',
decision: 'prompt-install',
source: 'npm-global',
}));
Expand Down Expand Up @@ -915,7 +915,7 @@ describe('runUpdatePreflight', () => {
expect.objectContaining({ target: { version: '0.5.0' } }),
);
expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({
latest: '0.5.0',
target_version: '0.5.0',
rollout_bucket: expect.any(Number),
rollout_delay_seconds: 0,
rollout_from_manifest: true,
Expand Down Expand Up @@ -945,7 +945,7 @@ describe('runUpdatePreflight', () => {
expect.objectContaining({ target: { version: '0.7.0' } }),
);
expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({
latest: '0.7.0',
target_version: '0.7.0',
rollout_bucket: expect.any(Number),
rollout_delay_seconds: 43_200,
rollout_from_manifest: true,
Expand Down
2 changes: 2 additions & 0 deletions apps/kimi-code/test/tui/kimi-tui-startup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,7 @@ describe('KimiTUI startup', () => {
});
expect(harness.track).toHaveBeenCalledWith('login', {
provider: 'managed:kimi-code',
method: 'oauth',
already_logged_in: false,
});
});
Expand Down Expand Up @@ -1302,6 +1303,7 @@ describe('KimiTUI startup', () => {
);
expect(harness.track).toHaveBeenCalledWith('login', {
provider: 'managed:kimi-code',
method: 'oauth',
already_logged_in: true,
});
});
Expand Down
2 changes: 1 addition & 1 deletion packages/acp-adapter/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ export class AcpSession {
// event so dashboards stay coherent.
this.emitTelemetry('question_dismissed');
} else {
this.emitTelemetry('question_answered');
this.emitTelemetry('question_answered', { answered: Object.keys(answer).length });
}
return answer;
} catch (err) {
Expand Down
6 changes: 3 additions & 3 deletions packages/acp-adapter/test/session-question-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe('AcpSession.handleQuestion', () => {
expect(req.toolCall.content).toEqual([
{ type: 'content', content: { type: 'text', text: '哪个口味?' } },
]);
expect(trackCalls).toEqual([{ event: 'question_answered', properties: undefined }]);
expect(trackCalls).toEqual([{ event: 'question_answered', properties: { answered: 1 } }]);
});

it('skip: q0_skip resolves to null with question_dismissed telemetry', async () => {
Expand Down Expand Up @@ -207,7 +207,7 @@ describe('AcpSession.handleQuestion', () => {
// Telemetry: degraded(multi_question) first, then answered.
expect(trackCalls).toEqual([
{ event: 'question_degraded', properties: { reason: 'multi_question', dropped: 2 } },
{ event: 'question_answered', properties: undefined },
{ event: 'question_answered', properties: { answered: 1 } },
]);
// log.warn fired with the dropped count.
expect(warnSpy).toHaveBeenCalledWith(
Expand Down Expand Up @@ -236,7 +236,7 @@ describe('AcpSession.handleQuestion', () => {
expect(raw.permissionRequests).toHaveLength(1);
expect(trackCalls).toEqual([
{ event: 'question_degraded', properties: { reason: 'multi_select' } },
{ event: 'question_answered', properties: undefined },
{ event: 'question_answered', properties: { answered: 1 } },
]);
});

Expand Down
31 changes: 19 additions & 12 deletions packages/agent-core/src/agent/compaction/full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '#/errors';
import {
APIEmptyResponseError,
inputTotal,
isRetryableGenerateError,
type GenerateResult,
type Message,
Expand Down Expand Up @@ -413,29 +414,35 @@ export class FullCompaction {
tokensAfter,
};

// Telemetry keys are snake_case, but the `context.apply_compaction`
// record written below keeps its persisted camelCase field names
// (consumed by external projectors). The two channels intentionally
// diverge — don't rename the record side to match.
this.agent.telemetry.track('compaction_finished', {
tokensBefore: result.tokensBefore,
tokensAfter: result.tokensAfter,
source: data.source,
tokens_before: result.tokensBefore,
tokens_after: result.tokensAfter,
duration_ms: Date.now() - startedAt,
compactedCount: result.compactedCount,
retryCount,
compacted_count: result.compactedCount,
retry_count: retryCount,
round,
thinkingLevel: this.agent.config.thinkingLevel,
...usage,
...data,
thinking_level: this.agent.config.thinkingLevel,
...(usage === null
? {}
: { input_tokens: inputTotal(usage), output_tokens: usage.output }),
});
this.agent.context.applyCompaction(result);
return result;
} catch (error) {
if (isAbortError(error)) return;
this.agent.telemetry.track('compaction_failed', {
...data,
tokensBefore,
source: data.source,
tokens_before: tokensBefore,
duration_ms: Date.now() - startedAt,
round,
retryCount,
thinkingLevel: this.agent.config.thinkingLevel,
errorType: error instanceof Error ? error.name : 'Unknown',
retry_count: retryCount,
thinking_level: this.agent.config.thinkingLevel,
error_type: error instanceof Error ? error.name : 'Unknown',
});
if (isKimiError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
throw new KimiError(ErrorCodes.COMPACTION_FAILED, String(error), { cause: error });
Expand Down
18 changes: 12 additions & 6 deletions packages/agent-core/src/agent/compaction/micro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class MicroCompaction {
const previousEffect = this.measureEffect(history, previousCutoff);
const rawContextTokens = estimateTokensForMessages(history);
// Whole-context length before/after this cutoff change, mirroring the
// `tokensBefore`/`tokensAfter` fields on `compaction_finished` so the
// `tokens_before`/`tokens_after` fields on `compaction_finished` so the
// two compaction paths can be compared on the same axis.
const tokensBefore =
rawContextTokens -
Expand All @@ -82,15 +82,21 @@ export class MicroCompaction {
effect.truncatedToolResultTokensBefore +
effect.truncatedToolResultTokensAfter;
this.agent.telemetry.track('micro_compaction_finished', {
...config,
...effect,
tokensBefore,
tokensAfter,
keep_recent_messages: config.keepRecentMessages,
min_content_tokens: config.minContentTokens,
cache_missed_threshold_ms: config.cacheMissedThresholdMs,
truncated_marker: config.truncatedMarker,
min_context_usage_ratio: config.minContextUsageRatio,
truncated_tool_result_count: effect.truncatedToolResultCount,
truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
tokens_before: tokensBefore,
tokens_after: tokensAfter,
previous_cutoff: previousCutoff,
cutoff: nextCutoff,
message_count: history.length,
cache_age_ms: cacheAgeMs,
thinkingLevel: this.agent.config.thinkingLevel,
thinking_level: this.agent.config.thinkingLevel,
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/agent-core/src/agent/tool/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ export class ToolManager {
...base,
outcome: 'error',
duration_ms: Date.now() - startedAt,
error: error instanceof Error ? error.message : String(error),
error_type: error instanceof Error ? error.name : 'Unknown',
});
throw error;
}
Expand Down
23 changes: 10 additions & 13 deletions packages/agent-core/src/rpc/core-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1141,19 +1141,16 @@ function telemetryErrorReason(error: unknown): string {

function clientTelemetryProperties(client: ClientTelemetryInfo | undefined): TelemetryProperties {
if (client === undefined) return {};
const properties: Record<string, string> = {};
addNonEmpty(properties, 'client_id', client.id);
addNonEmpty(properties, 'client_name', client.name);
addNonEmpty(properties, 'client_version', client.version);
addNonEmpty(properties, 'ui_mode', client.uiMode);
return properties;
}

function addNonEmpty(target: Record<string, string>, key: string, value: string | undefined): void {
const trimmed = value?.trim();
if (trimmed !== undefined && trimmed.length > 0) {
target[key] = trimmed;
}
// Emit a fixed key set (null when the client did not provide a field) so
// `session_started` has a stable schema across clients, matching the harness
// producer in `kimi-harness.ts`. Other session events also inherit these as
// context properties, so they share the same stable client-attribution shape.
return {
client_id: client.id ?? null,
client_name: client.name ?? null,
client_version: client.version ?? null,
ui_mode: client.uiMode ?? null,
};
}

async function resumeSessionResult(
Expand Down
49 changes: 23 additions & 26 deletions packages/agent-core/test/agent/compaction/full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,14 @@ describe('FullCompaction', () => {
event: 'compaction_finished',
properties: expect.objectContaining({
source: 'manual',
instruction: 'Keep the important test facts.',
tokensBefore: 39,
tokensAfter: 5,
tokens_before: 39,
tokens_after: 5,
duration_ms: expect.any(Number),
compactedCount: 6,
retryCount: 0,
thinkingLevel: 'off',
inputOther: 520,
output: 8,
inputCacheRead: 0,
inputCacheCreation: 0,
compacted_count: 6,
retry_count: 0,
thinking_level: 'off',
input_tokens: 520,
output_tokens: 8,
}),
});
await ctx.expectResumeMatches();
Expand Down Expand Up @@ -514,8 +511,8 @@ describe('FullCompaction', () => {
event: 'compaction_finished',
properties: expect.objectContaining({
source: 'manual',
tokensBefore: 25,
retryCount: 1,
tokens_before: 25,
retry_count: 1,
}),
});
await ctx.expectResumeMatches();
Expand Down Expand Up @@ -650,8 +647,8 @@ describe('FullCompaction', () => {
event: 'compaction_failed',
properties: expect.objectContaining({
source: 'manual',
retryCount: 4,
errorType: 'APIEmptyResponseError',
retry_count: 4,
error_type: 'APIEmptyResponseError',
}),
});
// No summary was ever applied; the original history is left intact.
Expand Down Expand Up @@ -764,16 +761,16 @@ describe('FullCompaction', () => {
event: 'compaction_failed',
properties: expect.objectContaining({
source: 'manual',
tokensBefore: 25,
tokens_before: 25,
duration_ms: expect.any(Number),
round: 1,
retryCount: 0,
errorType: 'Error',
retry_count: 0,
error_type: 'Error',
}),
});
expect(
records.find((record) => record.event === 'compaction_failed')?.properties,
).not.toHaveProperty('tokensAfter');
).not.toHaveProperty('tokens_after');
await ctx.expectResumeMatches();
});

Expand Down Expand Up @@ -878,10 +875,10 @@ describe('FullCompaction', () => {
event: 'compaction_failed',
properties: expect.objectContaining({
source: 'manual',
tokensBefore: 25,
tokens_before: 25,
duration_ms: expect.any(Number),
retryCount: 4,
errorType: 'APIConnectionError',
retry_count: 4,
error_type: 'APIConnectionError',
}),
});
await ctx.expectResumeMatches();
Expand Down Expand Up @@ -1212,10 +1209,10 @@ describe('FullCompaction', () => {
event: 'compaction_finished',
properties: expect.objectContaining({
source: 'auto',
tokensBefore: 46,
tokensAfter: 28,
compactedCount: 4,
retryCount: 0,
tokens_before: 46,
tokens_after: 28,
compacted_count: 4,
retry_count: 0,
}),
});
await ctx.expectResumeMatches();
Expand Down Expand Up @@ -1740,7 +1737,7 @@ describe('FullCompaction', () => {
event: 'compaction_finished',
properties: expect.objectContaining({
source: 'auto',
thinkingLevel: 'high',
thinking_level: 'high',
}),
});
});
Expand Down
Loading
Loading