Skip to content

feat(kimi-code): add /connect command with bundled model catalog#30

Open
7Sageer wants to merge 14 commits into
mainfrom
feat/connect-model-catalog
Open

feat(kimi-code): add /connect command with bundled model catalog#30
7Sageer wants to merge 14 commits into
mainfrom
feat/connect-model-catalog

Conversation

@7Sageer
Copy link
Copy Markdown
Collaborator

@7Sageer 7Sageer commented May 25, 2026

Summary

  • Add /connect command that configures a provider + model from a models.dev-compatible catalog, with model metadata (context window, output limit, capabilities) filled in automatically.
  • Bundle a pruned catalog snapshot at release time so /connect works offline by default and is not gated by models.dev availability; --refresh opts in to fetching the latest catalog from models.dev (falling back to the bundled snapshot on failure).
  • Polish: filter unsupported providers from the picker, share search and pagination across list pickers, and show a hint pointing to /login (Kimi) and /connect (other providers) when /model is opened with no configured models.

Test plan

  • pnpm typecheck clean
  • pnpm test — 850 passed
  • pnpm lint — 0 warnings
  • Manual: /connect loads the bundled catalog with no network
  • Manual: /connect --refresh fetches from models.dev
  • Manual: /connect --url=<custom> honors explicit URLs and surfaces fetch errors
  • Manual: /model with no models shows the new hint
截屏2026-05-25 19 21 54 截屏2026-05-25 19 22 25 截屏2026-05-25 19 22 40

7Sageer added 7 commits May 25, 2026 16:33
Add a /connect slash command that configures a provider and model
from a models.dev-style catalog. Users no longer need to hand-write
model metadata (context window, output limit, capabilities).

Architecture (3 layers):
- kosong: pure data layer — Catalog schema, inferWireType,
  catalogModelToCapability
- node-sdk: IO + config write — fetchCatalog, applyCatalogProvider,
  catalogModelToAlias
- app: TUI flow — /connect command, provider/model selection,
  credential input, config persistence

UI improvements in this PR:
- ChoicePickerComponent: add searchable (fuzzy filter + search bar)
- ModelSelectorComponent: add searchable (same)
- Extract reusable paging.ts for list pagination

Changesets included for kosong, kimi-code-sdk, and kimi-code.
When the network is unavailable, /connect now falls back to a built-in
snapshot of the models.dev catalog.

- `scripts/update-catalog.mjs`: fetches models.dev/api.json, strips
  unnecessary fields, and writes `src/built-in-catalog.ts` with the
  JSON string as a TS constant.
- `loadBuiltInCatalog(text?)` in node-sdk: parses the JSON string safely;
  returns undefined on any failure.
- `handleConnectCommand`: on fetch failure, shows an informative offline
  message and tries the built-in snapshot.
- The snapshot file is a placeholder (`undefined`) in source control;
  `update-catalog.mjs` populates it before release builds so the actual
  catalog is inlined into the bundle by rolldown.
ChoicePicker and ModelSelector each carried their own copy of the cursor +
fuzzy-search + pagination state machine. Extract it into a reusable
SearchableList so both pickers share one implementation; behavior is unchanged.
Replace the bare "No models configured." error with a notice that
points users to /login for Kimi and /connect for other providers.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 25, 2026

🦋 Changeset detected

Latest commit: f037ea6

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

This PR includes changesets to release 4 packages
Name Type
@moonshot-ai/kosong Minor
@moonshot-ai/kimi-code-sdk Minor
@moonshot-ai/kimi-code Minor
@moonshot-ai/agent-core 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

Copy link
Copy Markdown

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

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: a50f2ae029

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +5293 to +5295
if (options.length === 0) {
resolve(undefined);
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.

P2 Badge Report unsupported catalogs instead of silently returning

If a custom catalog only contains providers that inferWireType cannot map, options becomes empty and this function resolves undefined, after which handleConnectCommand exits immediately. In that case /connect --url=... appears to do nothing (no picker, no error, no hint), which makes troubleshooting impossible for users of private or partially compatible catalogs; showing an explicit error/status here would make the failure actionable.

Useful? React with 👍 / 👎.

Comment on lines +27 to +31
const refreshRequested = REFRESH_FLAG_RE.test(trimmed);
return {
url: DEFAULT_CATALOG_URL,
preferBuiltIn: !refreshRequested,
allowBuiltInFallback: true,
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 Reject --url when no value is provided

When users run /connect --url or /connect --url=, the URL regex does not match, so explicitUrl stays undefined and the parser silently falls back to the default catalog path. This can lead to configuring a provider from the built-in/default catalog even though the user intended a custom source, and there is no error indicating the argument was malformed.

Useful? React with 👍 / 👎.

7Sageer added 3 commits May 25, 2026 19:42
…catalog

# Conflicts:
#	apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts
Two silent-failure cases in /connect could leave users without any
feedback to act on:

- Reject `--url` when its value is missing (e.g. `/connect --url` or
  `/connect --url=`). Previously the argument parser silently fell
  back to the default catalog, so a malformed flag still appeared to
  succeed but with the wrong source.
- Show an explicit error when the resolved catalog yields no providers
  with supported wire types. Previously the picker resolved with no
  selection and the command returned without any UI feedback.
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

this.showStatus('Nothing to logout.');
}

P1 Badge Allow /logout to remove providers added by /connect

After /connect writes a non-managed provider (for example openai), /logout falls through to "Nothing to logout." because it only handles managed:kimi-code and isOpenPlatformId(...). This leaves users unable to clear API keys/providers they just configured through the new flow, which is a functional regression introduced by making custom providers first-class in the UI.

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,51 @@
import { DEFAULT_CATALOG_URL } from '@moonshot-ai/kimi-code-sdk';

const CATALOG_URL_FLAG_RE = /--url(?:=|\s+)(\S+)/;
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 Reject flag tokens consumed as --url values

resolveConnectCatalogRequest treats any non-space token after --url as a URL, so /connect --url --refresh parses --refresh as request.url and bypasses the missing-value error path. That leads to an attempted fetch of an invalid URL and disables built-in fallback (allowBuiltInFallback: false), producing a confusing failure instead of the intended “--url requires a value” validation.

Useful? React with 👍 / 👎.

if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
throw new Error(`Unexpected catalog response from ${url}.`);
}
return payload as Catalog;
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 Validate catalog entry shapes before returning payload

fetchCatalog only checks that the top-level JSON is an object, then casts it to Catalog without validating provider entry values. For custom catalogs (e.g. /connect --url=...) containing null or non-object provider values, downstream calls like inferWireType(entry) will throw on property access, surfacing an internal runtime error instead of a catalog-format error; this should be rejected at fetch/parse time.

Useful? React with 👍 / 👎.

certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}

- name: Generate built-in catalog (release artifacts)
if: inputs.sign-macos
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 Scope catalog generation to signed macOS release jobs

In the _native-build.yml matrix, the catalog-generation step runs whenever inputs.sign-macos is true, including Linux and Windows targets that later take the local-profile build path. This injects an unnecessary external fetch dependency into those jobs, so a transient models.dev failure can fail non-macOS artifact builds that do not consume the generated catalog.

Useful? React with 👍 / 👎.

7Sageer added 3 commits May 25, 2026 20:20
After /connect writes a non-managed provider (e.g. openai), /logout
fell through to "Nothing to logout." because the handler only matched
the managed default and isOpenPlatformId branches, leaving users no
in-app way to drop the API key and model aliases they just configured.

Collapse the OpenPlatform branch into a generic "provider is present
in config" check so any non-managed provider in config — OpenPlatform
OAuth targets and /connect catalog providers — goes through the same
removeProvider path.
`resolveConnectCatalogRequest` previously matched any non-space token
after `--url` as the URL, so `/connect --url --refresh` parsed
`--refresh` as the value and bypassed the missing-value error path.
Bare non-URL tokens (`/connect --url not-a-url`) and non-http(s)
schemes were also silently accepted.

Constrain the captured value to `https?://...` so flag-like and
non-URL tokens fall through to the existing `URL_FLAG_PRESENT_RE`
check and surface a clear error.
The catalog-generation step ran whenever `inputs.sign-macos` was true,
including Linux and Windows targets that take the local-profile build
path and never consume the generated catalog. A transient models.dev
outage would therefore fail unrelated artifact builds.

Match the condition to the macOS signed release-profile build that
actually consumes the bundled catalog.
Copy link
Copy Markdown

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

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: bad6c803c0

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/_native-build.yml Outdated
# path consumes the bundled catalog. Running this on Linux/Windows
# would make their builds fail on transient models.dev outages
# without providing any benefit.
if: runner.os == 'macOS' && inputs.sign-macos
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 Generate built-in catalog for all released native targets

The new catalog step is gated to runner.os == 'macOS' && inputs.sign-macos, but this workflow still publishes Linux/Windows artifacts built through the local-profile path (build:native:sea), and apps/kimi-code/scripts/native/build.mjs only auto-generates the catalog for profile === 'release'. As a result, non-macOS release binaries are built without KIMI_CODE_BUILT_IN_CATALOG_FILE, leaving BUILT_IN_CATALOG_JSON undefined at runtime and breaking the intended offline-by-default /connect behavior on those targets.

Useful? React with 👍 / 👎.

Comment on lines +44 to +49
- name: Generate Kimi Code built-in catalog
shell: bash
run: |
CATALOG_FILE="$RUNNER_TEMP/kimi-code-built-in-catalog.json"
node apps/kimi-code/scripts/update-catalog.mjs --out "$CATALOG_FILE"
echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV"
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 Avoid blocking all releases on catalog fetch availability

The release workflow now unconditionally fetches models.dev before any package build/publish step, so a transient outage or network failure at that endpoint fails the entire monorepo release job (including unrelated packages). Because the catalog is only needed for embedding into Kimi Code artifacts, this new always-on external dependency can halt normal release operations even when no Kimi Code package is being shipped.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

@7Sageer 7Sageer May 25, 2026

Choose a reason for hiding this comment

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

By design — /connect offline-by-default is a release-time commitment. If the catalog can't be fetched, the produced binaries would silently lose offline behavior, which is a degraded release and should block. The right response to a transient models.dev outage here is to retry the release, not decouple the dependency. Coupling unrelated packages (kosong, agent-core, etc.) to catalog availability is the cost of a single release pipeline; we prefer that over silently shipping degraded kimi-code.

The earlier narrowing to `runner.os == 'macOS' && inputs.sign-macos`
relied on a misread of build.mjs: its `profile === 'release'` guard
only auto-fetches the catalog as a dev fallback. Whether the binary
actually embeds the catalog is decided by tsdown's define at bundle
time, which reads KIMI_CODE_BUILT_IN_CATALOG_FILE regardless of
profile.

Linux and Windows release artifacts therefore lost their bundled
catalog and silently regressed offline /connect on those targets.
Restore generation for all OS jobs when sign-macos is true.
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