Skip to content

fix(kimi-code): queue submissions until the slash-command catalog is ready - #3480

Draft
7Sageer wants to merge 1 commit into
mainfrom
fix/tui-dynamic-commands-ready
Draft

fix(kimi-code): queue submissions until the slash-command catalog is ready#3480
7Sageer wants to merge 1 commit into
mainfrom
fix/tui-dynamic-commands-ready

Conversation

@7Sageer

@7Sageer 7Sageer commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No tracking issue — internal fix from a CI/harness race analysis: slash commands submitted right after TUI startup could be mis-dispatched as plain user prompts when the async skill/plugin catalog had not finished loading.

Problem

At TUI startup, refreshSkillCommands / refreshPluginCommands load the dynamic command catalog asynchronously (nothing blocks the UI), while dispatchInput reads skillCommandMap synchronously. A submission arriving before the catalog settles (a ~230ms window in the harness, unbounded under CPU saturation) is treated as unknown slash text and sent to the model as a plain user prompt — the skill activation is silently lost. Fast typists hit the same race.

What changed

  • dispatchInput defers every submission while dynamicCommandsReady is pending; queued drains re-dispatch in submission order once the gate clears, so global input ordering is preserved. The ready path is byte-identical to before.
  • KimiTUI.refreshDynamicCommands arms the gate over the combined skill+plugin refresh via createDynamicCommandsGate: the gate is infallible (load success or failure both resolve it, so queued input can never be dropped by a rejection) and carries a 10s fallback — on timeout the gate clears and a warning is shown (Skill and plugin catalogs are still loading — slash commands may be incomplete for a moment.), so a wedged catalog load (e.g. stuck IPC) can never block input forever. A load that settles after the timeout still applies its results.
  • Both startup paths (finishStartup, post-login bootstrap in auth-flow) arm the gate through refreshDynamicCommands; mid-session refreshes keep calling the individual methods since the maps are already populated.
  • Tests: dispatch-level integration in goal.test.ts (defers while pending, FIFO drain order, plain-text ordering relative to slash submissions) and gate unit tests in dynamic-commands-gate.test.ts (timeout warning fires once, settle-before-timeout stays quiet, load rejection still resolves the gate).

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (no tracking issue; problem described above from a harness/CI race analysis).
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset. (changeset included: @moonshot-ai/kimi-code patch)
  • Ran gen-docs skill, or this PR needs no doc update. (internal timing fix, no user-facing behavior change beyond the fix itself)

…ready

At TUI startup the dynamic (skill/plugin) command catalog loads
asynchronously while dispatchInput reads skillCommandMap synchronously,
so a slash command submitted inside that window was mis-dispatched to
the model as a plain user prompt.

dispatchInput now defers submissions while dynamicCommandsReady is
pending and drains them in submission order once the gate clears; the
ready path is unchanged. The gate is infallible and carries a 10s
fallback that clears it with a warning, so a wedged catalog load can
never queue input forever. Startup and post-login bootstrap both arm
the gate via refreshDynamicCommands.
@7Hanrui

7Hanrui commented Sep 2, 2026

Copy link
Copy Markdown

@codex review

@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 946b949

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

@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: 946b949e2d

ℹ️ 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 +232 to +234
void pending.then(() => {
dispatchInput(host, text);
});

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 Serialize deferred submissions before redispatching

When multiple inputs arrive during this gate, these independent promise callbacks preserve only callback-start order, not actual submission order. For example, with an active session, if the first prompt contains freshly pasted media, sendNormalUserInput pauses at pendingMediaIngestions (lines 1352–1364), while a following plain prompt proceeds synchronously and starts the turn; when the first resumes, it is queued behind the second. Drain deferred inputs serially through the point where each input is accepted or queued so the FIFO guarantee is maintained for asynchronous preparation paths.

Useful? React with 👍 / 👎.

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.

2 participants