Visitar URL original
feat(kap-server): expose host telemetry and image limits by kimi-agent-bot · Pull Request #4852 · MoonshotAI/kimi-code · GitHub
Skip to content

feat(kap-server): expose host telemetry and image limits - #4852

Open
kimi-agent-bot wants to merge 10 commits into
feat/kap-host-extensionfrom
feat/kap-host-telemetry
Open

kimi-agent-bot wants to merge 10 commits into
feat/kap-host-extensionfrom
feat/kap-host-telemetry

Conversation

@kimi-agent-bot

Copy link
Copy Markdown
Collaborator

Requirement or Bug

Desktop 的遥测 wiring 和内置浏览器截图编码仍直接读取 agent-core-v2 的配置、OAuth、遥测、工作区 Service 和内部图片预算。

本 PR 在 kap-server 增加公开 hostTelemetry 视图,并公开截图边长与字节预算。Desktop 后续可以删除这些内部依赖,不需要兼容层或深路径 import。

本 PR 以 #4851 的 feat/kap-host-extension 为 base,只包含遥测和图片预算这一层改动。

Bug Reproduction Steps

N/A(公开宿主能力扩展)。

Root Cause

N/A(公开宿主能力扩展)。

Code Changes

  • RunningServer.hostTelemetry 提供:
    • telemetry consent 读取。
    • 缓存 OAuth access token 读取。
    • cloud appender 创建与安装。
    • 普通 telemetry event 记录。
    • 当前工作区会话计数。
    • telemetry shutdown。
  • kap-server 根入口公开 IMAGE_BYTE_BUDGET 和 resolveMaxImageEdgePx,供 Desktop 截图编码使用。
  • 使用公开 @moonshot-ai/kimi-telemetry 的 TelemetryProperties 类型,不让 Desktop 重新引用 core 的类型定义。

现有 server 是否创建该公开视图不改变 REST、WebSocket、CLI、默认配置或持久化行为。

Behavior Changes and Affected Users

None。此 PR 只增加嵌入式宿主读取能力,未修改现有 telemetry 事件、上传策略、默认值或客户端请求。TUI、desktop、web、VS Code、ACP 和 SDK 的现有路径不变。

真实 server 测试覆盖:

  • 默认 consent、无缓存 token、空工作区会话计数。
  • cloud appender 创建。
  • 新建会话后的计数。
  • 公开图片预算。
  • 既有 Host Extension 的会话、提醒和工具行为。
  • kap-server typecheck、build 和变更 lint 均通过。

无用户可见变化,无需 changeset;无 REST、CLI 或文档站变化。

Checklist

  • I have read the CONTRIBUTING document.
  • This PR adds an internal host contract and has no independent issue.
  • I have added tests for the new host view and public image limits.
  • No existing behavior is removed or flipped.
  • Ran gen-changesets skill; no user-facing changeset is needed.
  • No REST, CLI or documentation-site update is needed.

@changeset-bot

changeset-bot Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1a667f2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-11T18:50:45.630451Z 1a667f2 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@1a667f2
npx https://pkg.pr.new/@moonshot-ai/kimi-code@1a667f2

commit: 1a667f2

@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: 752b8d1c3d

ℹ️ 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 +26 to +30
export interface HostCloudAppenderOptions {
readonly deviceId: string;
readonly appName: string;
readonly uiMode?: string;
readonly getAccessToken: () => string | null | Promise<string | null>;

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 Preserve model context in the host appender API

When Desktop replaces its direct core call with this API, HostCloudAppenderOptions cannot carry the configured model even though the underlying CloudAppenderHostOptions accepts model and every existing telemetry initializer supplies it. Because createCloudAppender simply forwards these narrowed options and HostTelemetry exposes no other way to set ambient model context, events emitted through the new host appender silently lose their model dimension, degrading telemetry attribution and experiment results; expose and forward model (or derive it from configuration) before this becomes the replacement path.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 96d744c 修复:HostCloudAppenderOptions 支持 model,HostTelemetry 暴露 defaultModel,Desktop 创建 appender 时传入默认模型。

Comment on lines +48 to +51
readConsent: async () => {
await config.ready;
try {
return config.get('telemetry');

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 Honor the telemetry-disable environment override

When an embedded host uses readConsent() to decide whether to install the new cloud appender, a user launching it with KIMI_DISABLE_TELEMETRY=1 still receives the config value (often undefined) and telemetry can be uploaded despite the explicit opt-out. The existing kap-server initializer combines config.get('telemetry') with IBootstrapService.getEnv('KIMI_DISABLE_TELEMETRY'), but this replacement view exposes only the former; return the effective consent or otherwise expose and enforce the environment override before allowing appender installation.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 96d744c 修复:readConsent 同时检查 KIMI_DISABLE_TELEMETRY 的真值集合与 config;新增环境禁用测试。

Comment on lines +60 to +62
countSessions: async () => {
const workspaces = await core.accessor.get(IWorkspaceService).list();
return core.accessor.get(ISessionIndex).count({ workspaceIds: workspaces.map((workspace) => workspace.id) });

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 Count archived and aliased sessions in host telemetry

For users with archived sessions or legacy workspace-ID aliases, this reports fewer sessions than actually belong to their workspaces: ISessionIndex.count excludes archived rows by default, and passing only catalog IDs bypasses the alias folding performed by IWorkspaceSessions.count. The existing workspace API deliberately resolves alias IDs and sets includeArchived: true, so this new host metric will misclassify long-lived users and corrupt session-count telemetry; reuse that service or apply both behaviors here.

AGENTS.md reference: AGENTS.md:L110-L112

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 96d744c 修复:会话计数改用 IWorkspaceSessions.count,覆盖 workspace alias 和 includeArchived;新增归档后计数不变测试。

readConsent(): Promise<unknown>;
getCachedAccessToken(): Promise<string | null>;
createCloudAppender(options: HostCloudAppenderOptions): HostTelemetryAppender;
addAppender(appender: HostTelemetryAppender): void;

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 Return the appender registration to the host

When a host needs to replace or tear down its appender without shutting down the entire server telemetry service, this void signature hides the IDisposable returned by ITelemetryService.addAppender, leaving the old appender permanently registered. Stopping its periodic flush does not stop track() calls, so later events continue accumulating in the detached appender and reinitialization can duplicate delivery; return a public disposable registration as the underlying API does.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 96d744c 修复:addAppender 返回公开 disposable,Desktop shutdown 时注销 registration。

const workspaces = await core.accessor.get(IWorkspaceService).list();
return core.accessor.get(ISessionIndex).count({ workspaceIds: workspaces.map((workspace) => workspace.id) });
},
shutdown: () => telemetry.shutdown(),

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 Apply a timeout to host telemetry shutdown

If the host-supplied getAccessToken promise or a telemetry send never settles while buffered events exist, this direct call to ITelemetryService.shutdown() never resolves and can hang Desktop shutdown indefinitely. Kap-server's existing telemetry lifecycle explicitly races appender shutdown against a three-second deadline and has a regression test with a never-resolving token, but the replacement host path exposes no timeout or abort mechanism; preserve that bounded-shutdown behavior here.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 96d744c 修复:hostTelemetry.shutdown 内置 3 秒上限,Desktop 原有 raceTimeout 保留;新增永不 resolve 的 shutdown 测试。

@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: 96d744c4fe

ℹ️ 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 +28 to +29
retryDiskEvents(): Promise<void>;
}

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 Expose per-appender shutdown

When Desktop replaces or tears down its telemetry appender while the server remains alive, this narrowed interface hides the CloudAppender.shutdown() needed to flush its buffer. The established lifecycle in services/telemetry.ts disposes the registration and then shuts down that specific appender; with this API, disposing the registration first means hostTelemetry.shutdown() can no longer reach it, silently dropping buffered events, while calling the global shutdown first also shuts every unrelated appender. Expose per-appender shutdown or return an owned asynchronous teardown handle.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD c2adcb6 修复:HostTelemetryAppender 暴露 shutdown();Desktop 注销 registration 后调用该 appender.shutdown(),不再调用全局 shutdown。新增接口与关闭测试。

Comment thread packages/kap-server/src/index.ts Outdated
HostTelemetryAppender,
HostTelemetryRecord,
} from './hostTelemetry';
export { IMAGE_BYTE_BUDGET, resolveMaxImageEdgePx } from '@moonshot-ai/agent-core-v2/agent/media/image-compress';

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 Resolve the image limit from the server configuration

When Desktop asks for this limit before any agent has been created, resolveMaxImageEdgePx() returns the module default (or a stale value from another agent) rather than this server's [image].max_edge_px or KIMI_IMAGE_MAX_EDGE_PX setting. The only code that populates the function's module-global value is ImageConfigBridge, which is registered at LifecycleScope.Agent, while startServer() creates only the app scope before exposing this export. A host that sizes screenshots during startup therefore silently ignores the user's configured limit; expose a resolver bound to the server's IConfigService instead.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD c2adcb6 修复:HostTelemetry.resolveMaxImageEdgePx 绑定当前 server 的 IConfigService,Desktop 启动时读取并配置截图编码。测试使用 KIMI_IMAGE_MAX_EDGE_PX=1234 验证。

@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: 7afafa4ca2

ℹ️ 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 +248 to +249
const execution = await tool.resolveExecution(args);
if (!('execute' in execution)) return;

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 decorated resolver failures

When the decorator produces arguments for which tool.resolveExecution() returns an ExecutableToolErrorResult—for example, because the injected trusted context is invalid—this branch simply returns while context.prepared still contains the execution resolved from the original arguments. The server then executes the undecorated action instead of reporting the resolver failure, silently dropping the host-supplied context; stop the call with the returned error rather than retaining the old execution.

AGENTS.md reference: AGENTS.md:L130-L132

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 修复:装饰后的 resolver 若返回错误,permitting 阶段直接返回 executor 拒绝结果,不再保留或执行原始动作。新增 HostResolverFailure 测试,断言返回 decorator rejected 且原 execute 未被调用。

@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: 88bc8818b9

ℹ️ 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".

decorateToolExecution: (toolName, decorator) => {
const registry = handle.accessor.get(IAgentToolRegistryService);
return handle.accessor.get(IAgentToolExecutorService).registerHook({
permitting: async (context) => {

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 Apply host decoration before the skippable permission phase

When an embedded host decorates Write or Edit in plan mode, PlanService.guardToolExecution() calls event.allow() for writes to the plan file; ToolExecutor translates that into skipPermitting and never invokes this hook, so the original undecorated execution runs silently. On calls that do enter permitting, the eagerly registered AgentPermissionGate precedes host callbacks and therefore authorizes the original execution before this hook replaces it. Move trusted decoration into a non-skippable pre-permission stage so it always runs and the decorated execution is the one being authorized.

AGENTS.md reference: AGENTS.md:L130-L132

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

starting

const execution = await tool.resolveExecution(args);
if (!('execute' in execution)) {
const message = typeof execution.output === 'string' ? execution.output : JSON.stringify(execution.output);
return { reject: message, result: toLegacyToolReturn(execution, toolName) };

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 Finalize decorated resolver errors before returning them

When decorated arguments make resolveExecution() return an error, converting it directly with toLegacyToolReturn bypasses LegacyExecutableToolAdapter.finalize(), which normally invokes IAgentToolResultTruncationService.truncateForModel() and normalizes empty or non-text output. A resolver error containing large text therefore enters tool history untruncated and is not spilled, potentially exhausting the next model request's context; route this result through the same finalizer as normal resolver results.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

resolver

@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: 90ad82bf1b

ℹ️ 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".

decorateToolArguments(
toolName: string,
decorator: (args: unknown, context: HostToolDecoratorContext) => unknown | Promise<unknown>,
decorator: (args: unknown, context: HostToolDecoratorContext) => unknown,

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 Keep async support for argument decorators

When a TypeScript host rebuilds an existing extension whose decorateToolArguments callback returns a promise, this narrowed public signature now rejects code that was accepted by the base contract, even though the implementation still awaits the callback. Preserve unknown | Promise<unknown> so existing asynchronous decorators remain source-compatible.

AGENTS.md reference: AGENTS.md:L110-L112

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已恢复

const message = typeof finalized.output === 'string' ? finalized.output : JSON.stringify(finalized.output);
return { reject: message, result: toLegacyToolReturn(finalized, toolName) };
}
Object.assign(context, { args });

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 Apply execution decoration after argument rewrites

When decorateToolArguments was registered earlier for the same tool, the hook composer has already marked the starting phase as rewritten; mutating its current context here makes the composer return the trusted decorated arguments, after which ToolExecutor calls prepare() again. For tools with additionalProperties: false, injected host-only fields are then schema-validated and the call fails before execution, while other tools may overwrite the decorated execution during re-prepare. Apply trusted execution decoration after argument rewrites have been prepared instead.

AGENTS.md reference: AGENTS.md:L110-L112

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已改为

@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: 76bc9b60c2

ℹ️ 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 message = typeof finalized.output === 'string' ? finalized.output : JSON.stringify(finalized.output);
return { reject: message, result: toLegacyToolReturn(finalized, toolName) };
}
executions.set(context.taskId, { args, execution });

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 Remove cached executions when calls stop before execution

When a decorated call is rejected by another starting hook or during permitting—for example, when the user denies approval—this entry is inserted but beforeExecute never runs, and that hook is the only place that deletes it. Each rejected call therefore retains its decorated arguments and runnable execution closure for the lifetime of the host-agent registration, causing unbounded memory growth in long-lived sessions; clean the entry when the task completes or avoid a side cache that depends on reaching beforeExecute.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

已在 HEAD 修复:afterExecute 统一按 taskId 清理缓存,覆盖成功、权限拒绝和失败路径,不再只在 beforeExecute 删除。

@kimi-agent-bot

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: 1a667f2406

ℹ️ 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.

1 participant