Skip to content

fix(telemetry): attribute session starts to the selected model - #4094

Draft
7Sageer wants to merge 3 commits into
mainfrom
fix/session-started-model
Draft

7Sageer wants to merge 3 commits into
mainfrom
fix/session-started-model

Conversation

@7Sageer

@7Sageer 7Sageer commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Requirement or Bug

Desktop 创建或恢复会话时的 session_started 缺少模型归因,创建请求显式指定的模型也会被忽略。

Bug Reproduction Steps

  1. 配置默认模型 example-model,通过 POST /api/v1/sessions 传入 agent_config.model: "mock-model"。
  2. 检查创建响应中的模型以及引擎发出的 session_started 记录。
  3. 修复前,创建响应的模型为空,指定模型未绑定,启动事件也没有事件级模型;未提供模型时还可能沿用上报器过期的默认值。

Root Cause

创建处理器没有把请求中的模型传给会话初始化,直接 SDK 调用也在引擎启动事件之后才绑定模型。模型只写入 Agent 的埋点上下文,而启动事件从 Session 层发出。上报器也没有区分未指定模型与明确未知的模型。本修改打通模型绑定与事件归因,不改变事件的生命周期触发时机。

Code Changes

POST /sessions
  → 非空模型在注册工作区前校验
  → 通过已有 mainAgentBinding 在创建完成前绑定
  → 创建响应返回实际绑定模型
SDK createSession
  → 通过可等待的创建事件先连接监听、完成初始配置
  → 保留配置警告转发,再生成启动事件;初始化失败仍向 SDK 调用方抛出
session_started
  → 已绑定的主 Agent 模型 / 当前默认模型 / unknown
  → 通过 withContext 生成单次快照,增加 model_source
CloudAppender
  → 显式 model=null 清除本事件的兜底模型

同步中英文服务端 API 文档,并增加真实创建/恢复路径与发送载荷的回归测试。

Behavior Changes and Affected Users

Behavior Before After Who relies on the old behavior Escape hatch
创建时指定非空模型 请求被接受,但模型被忽略,响应模型为空 创建完成前绑定、验证指定模型,响应返回实际模型 Desktop、Web 和直接调用创建 REST 接口的客户端 省略模型或传空字符串,保留原有空会话创建路径
创建时指定不存在的模型 被忽略,创建仍成功 注册工作区之前失败,不遗留新工作区或启动事件 发送过期或无效模型名称的 REST 调用方 指定已配置模型,或省略模型
直接 SDK 创建时的模型归因 初始模型在启动事件之后绑定 初始配置在事件快照之前完成,保持事件与交互监听先于绑定,原有绑定错误仍导致 SDK 调用失败 直接使用 SDKRpcClientV2 的调用方 无需修改调用方式
引擎启动事件的模型归因 Session 层缺少模型,可能依赖应用级兜底 记录主 Agent / 当前默认模型快照,附带 property_model_source Desktop、Web 及引擎事件消费者 模型确实未知时仍缺失;查询继续保留空值
显式未知模型 可能沿用上报器初始化时的模型 该事件不携带 context_model,其他事件的兜底保持原样 云端埋点消费者及 CloudAppender 调用方 不传模型仍保留既有兜底语义;只有显式 null 清除

未指定模型时不新增强制绑定;创建、恢复、重复打开活跃会话的事件计数保持原有语义。恢复使用已有主 Agent 绑定;后续切换模型不会改写启动快照。Desktop/Web 的现有客户端已经发送该创建参数,未增加请求字段或磁盘格式。Desktop 需要在后续内嵌核心版本更新中包含本提交。

验证:

  • 引擎埋点测试:52 个通过,覆盖最终 context_model 和单事件 null 清除。
  • 服务端会话与埋点测试:100 个通过,覆盖并发不同模型、动态默认模型、恢复历史模型、空会话、无效模型、工作区无残留及现有行为。
  • SDK v2 完整测试:68 个通过,覆盖 harness 去重、直接 SDK 事件转发,有/无默认模型时并发指定不同模型的归因,以及模型、thinking、permission 初始配置失败的拒绝语义。
  • agent-core-v2、kap-server、node-sdk 类型检查通过。
  • pnpm lint 通过,无错误;保留仓库现有警告。
  • pnpm --dir docs run build 通过,中英文说明保持同步。
  • git diff --check 通过。

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • The behavior-change table above is complete, and every removed behavior or flipped default is named in the changeset and either has an escape hatch or was explicitly approved by a maintainer in this PR.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

Copilot AI balanced review requested due to automatic review settings September 30, 2026 07:32
@changeset-bot

changeset-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c9eadb9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@7Hanrui

7Hanrui commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80b8b92498

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +340 to +342
const model = boundModel ?? (this.config.get<string>('defaultModel') || null);
const modelSource = boundModel !== undefined ? 'agent' : model !== null ? 'default' : 'unknown';
event.handle.accessor.get(ITelemetryService).withContext({ model }).track2('session_started', {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Attribute direct SDK starts to the requested model

For direct SDKRpcClientV2.createSession({ model }) calls, the SDK invokes ISessionManager.create without a mainAgentBinding and only materializes/binds input.model afterward (packages/node-sdk/src/sdk-rpc-client-v2.ts:1363-1379). This snapshot therefore reports defaultModel (or unknown) rather than the requested model; the SDK forwarding appender flattens that context into the event properties, so direct SDK telemetry is now incorrectly attributed whenever the requested model differs from the default. Pass the initial binding through or defer the startup event until after the SDK applies the model.

AGENTS.md reference: AGENTS.md:L98-L100

Useful? React with 👍 / 👎.

Comment on lines +243 to +247
const model = body.agent_config?.model || undefined;
const handle = await core.accessor.get(ISessionManager).create({
workspaceId: touched.id,
workDir,
mainAgentBinding: model === undefined ? undefined : { profile: DEFAULT_AGENT_PROFILE_NAME, model },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Roll back workspaces created for invalid requested models

When a client creates a session for an unregistered metadata.cwd with an unknown model, createOrTouch has already persisted and published the workspace before this binding reaches model validation. Session creation cleans up its session directory on that failure but does not remove the workspace, so the request returns an error while GET /workspaces subsequently exposes a workspace the user never successfully created. Validate the model before touching the workspace, or undo a newly created workspace on this failure path.

AGENTS.md reference: AGENTS.md:L98-L100

Useful? React with 👍 / 👎.

@7Hanrui

7Hanrui commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60a328c96e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const sessionId = input.id ?? `session_${randomUUID()}`;
const registration = manager.onDidCreateSession((event) => {
if (event.sessionId !== sessionId) return;
event.waitUntil((async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Propagate failed SDK session bindings

When a direct SDK caller supplies an unknown model (or any model/thinking/permission combination that makes materializeMainAgent reject), this listener puts the failure into waitUntil; AsyncEmitter only reports rejected waiters and still lets manager.create resolve. Before this change the same await ran after creation and rejected createSession, so callers now receive a successful, persisted session whose requested configuration was silently not applied. Propagate this promise's failure out of doCreateSession (while retaining the startup-event ordering) instead.

AGENTS.md reference: AGENTS.md:L118-L120

Useful? React with 👍 / 👎.

@7Hanrui

7Hanrui commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: c9eadb93b6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants