Repository navigation
feat(kap-server): expose host telemetry and image limits - #4852
kimi-agent-bot wants to merge 10 commits into
Conversation
|
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
There was a problem hiding this comment.
💡 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".
| export interface HostCloudAppenderOptions { | ||
| readonly deviceId: string; | ||
| readonly appName: string; | ||
| readonly uiMode?: string; | ||
| readonly getAccessToken: () => string | null | Promise<string | null>; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 96d744c 修复:HostCloudAppenderOptions 支持 model,HostTelemetry 暴露 defaultModel,Desktop 创建 appender 时传入默认模型。
| readConsent: async () => { | ||
| await config.ready; | ||
| try { | ||
| return config.get('telemetry'); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 96d744c 修复:readConsent 同时检查 KIMI_DISABLE_TELEMETRY 的真值集合与 config;新增环境禁用测试。
| countSessions: async () => { | ||
| const workspaces = await core.accessor.get(IWorkspaceService).list(); | ||
| return core.accessor.get(ISessionIndex).count({ workspaceIds: workspaces.map((workspace) => workspace.id) }); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 96d744c 修复:会话计数改用 IWorkspaceSessions.count,覆盖 workspace alias 和 includeArchived;新增归档后计数不变测试。
| readConsent(): Promise<unknown>; | ||
| getCachedAccessToken(): Promise<string | null>; | ||
| createCloudAppender(options: HostCloudAppenderOptions): HostTelemetryAppender; | ||
| addAppender(appender: HostTelemetryAppender): void; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 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(), |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 96d744c 修复:hostTelemetry.shutdown 内置 3 秒上限,Desktop 原有 raceTimeout 保留;新增永不 resolve 的 shutdown 测试。
# Conflicts: # packages/kap-server/test/hostExtension.test.ts
There was a problem hiding this comment.
💡 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".
| retryDiskEvents(): Promise<void>; | ||
| } |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD c2adcb6 修复:HostTelemetryAppender 暴露 shutdown();Desktop 注销 registration 后调用该 appender.shutdown(),不再调用全局 shutdown。新增接口与关闭测试。
| HostTelemetryAppender, | ||
| HostTelemetryRecord, | ||
| } from './hostTelemetry'; | ||
| export { IMAGE_BYTE_BUDGET, resolveMaxImageEdgePx } from '@moonshot-ai/agent-core-v2/agent/media/image-compress'; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD c2adcb6 修复:HostTelemetry.resolveMaxImageEdgePx 绑定当前 server 的 IConfigService,Desktop 启动时读取并配置截图编码。测试使用 KIMI_IMAGE_MAX_EDGE_PX=1234 验证。
There was a problem hiding this comment.
💡 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".
| const execution = await tool.resolveExecution(args); | ||
| if (!('execute' in execution)) return; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 修复:装饰后的 resolver 若返回错误,permitting 阶段直接返回 executor 拒绝结果,不再保留或执行原始动作。新增 HostResolverFailure 测试,断言返回 decorator rejected 且原 execute 未被调用。
There was a problem hiding this comment.
💡 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) => { |
There was a problem hiding this comment.
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 👍 / 👎.
| 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) }; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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, |
There was a problem hiding this comment.
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 👍 / 👎.
| const message = typeof finalized.output === 'string' ? finalized.output : JSON.stringify(finalized.output); | ||
| return { reject: message, result: toLegacyToolReturn(finalized, toolName) }; | ||
| } | ||
| Object.assign(context, { args }); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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 }); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
已在 HEAD 修复:afterExecute 统一按 taskId 清理缓存,覆盖成功、权限拒绝和失败路径,不再只在 beforeExecute 删除。
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
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提供: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 测试覆盖:
无用户可见变化,无需 changeset;无 REST、CLI 或文档站变化。
Checklist
gen-changesetsskill; no user-facing changeset is needed.