Skip to content

fix(node-sdk): bind --agent/--agent-file profile on interactive session create (v2) - #2832

Open
SnowingFox wants to merge 3 commits into
MoonshotAI:mainfrom
SnowingFox:fix/2765-interactive-agent-tools
Open

fix(node-sdk): bind --agent/--agent-file profile on interactive session create (v2)#2832
SnowingFox wants to merge 3 commits into
MoonshotAI:mainfrom
SnowingFox:fix/2765-interactive-agent-tools

Conversation

@SnowingFox

Copy link
Copy Markdown

Fixes #2765

Problem

Agent profile frontmatter tools (allowlist) and disallowedTools (denylist)
are enforced in -p print mode but completely ignored in interactive TUI
sessions. The interactive session is created through the SDK's agent-core-v2
client, and its createSession never bound the requested startup profile —
the main agent fell back to the default profile, so the model saw the full,
unrestricted tool set regardless of the profile's tool policy.

The profile's system prompt appeared to be applied because profile text can
still influence prompt rendering, but the tool policy (activation fold +
execution guard) is driven by the bound profile's tools / disallowedTools,
which were never applied in interactive mode.

Root cause

SDKRpcClientV2.createSession (the v2 engine client used by the interactive
TUI, run-shell.tscreateKimiHarnessV2) dropped
CreateSessionOptions.agentProfile / agentFiles entirely: it created the
session with no mainAgentBinding and materializeMainAgent always bound
DEFAULT_AGENT_PROFILE_NAME. Print mode (run-v2-print.ts), by contrast,
resolves the profile name and passes it into the session's mainAgentBinding,
so the tool policy is enforced there.

Fix

packages/node-sdk/src/sdk-rpc-client-v2.ts:

  • createSession now resolves the startup profile (--agent name, or the
    --agent-file's frontmatter name, mirroring run-v2-print.ts) and passes
    it to main-agent materialization, so the interactive session binds the same
    profile (and its tool policy) as print mode.
  • materializeMainAgent accepts the optional profile and binds it instead
    of unconditionally binding the default profile; an already-bound agent is
    left alone so the explicit binding is never overwritten.

Verification

  • New regression test packages/node-sdk/test/session-agent-profile.test.ts
    creates a v2 session with agentProfile pointing at a restricted profile
    and asserts the interactive main agent binds that profile (profileName +
    activeToolNames). It fails on the previous code (main agent bound the
    default profile) and passes with the fix.
  • Run: pnpm -C packages/node-sdk exec vitest run test/session-agent-profile.test.ts

Note: unrelated to the earlier open PR #2822 (hooks index rebuild), which
touches the hooks domain of agent-core-v2.

@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1c8e2d1

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-sdk 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

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

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

input.permission !== undefined
) {
const agent = await this.materializeMainAgent(handle, {
profile: agentProfileName,

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 Register --agent-file profiles before binding

When the TUI passes only agentFiles, this binds the parsed profile name, but SDKRpcClientV2 never registers those files with the v2 engine; the explicit profile loader reads only IBootstrapService.args.agentFiles, while this client bootstraps only skillDirs. In that context an arbitrary --agent-file profile is absent from the session catalog, so profile.bind rejects as an unknown profile and interactive --agent-file remains unusable unless the same profile is also discoverable from user/project agent dirs.

Useful? React with 👍 / 👎.

// materialized — the same binding print mode applies via `mainAgentBinding`
// — so a profile's `tools` / `disallowedTools` policy is enforced in
// interactive sessions too, not just `-p`.
const agentProfileName = await this.resolveStartupAgentProfile(input, workDir);

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 Clean up failed startup profile binds

When a newly selected startup profile is invalid or missing, the rejection now happens after ISessionLifecycleService.create() has already returned and indexed the session, because the profile is resolved/bound in the SDK instead of inside the lifecycle create call. In that scenario createSession({ id, agentProfile: 'missing-agent' }) returns an error but leaves a live/persisted session behind, so listSessions shows a failed create and the same id cannot be reused; either validate/bind before indexing via mainAgentBinding or close/remove the handle on failure.

Useful? React with 👍 / 👎.

…binding

The interactive --agent-file path resolved the profile name but never
registered the file with the v2 engine, so an agentfile supplied solely
through agentFiles was absent from the session catalog and profile.bind
rejected it as an unknown profile (chatgpt-codex-connector P1). Seed
input.agentFiles through the explicit agent loader channel
(IBootstrapService.args.agentFiles) and re-arm the workspace explicit
loader before binding, matching run-v2-print. Adds a regression test for
an agent-file-only profile that binds as the interactive main agent.

Signed-off-by: snowingfox <1503401882@qq.com>
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.

[Bug]: Agent profile tools/disallowedTools ignored in interactive mode (works in -p mode with KIMI_CODE_EXPERIMENTAL_FLAG=1)

1 participant