Skip to content

feat(sdk): add get_available_models() to Python and TypeScript SDKs - #6460

Closed
juhuan wants to merge 1 commit into
QwenLM:mainfrom
juhuan:feat/sdk-get-available-models
Closed

feat(sdk): add get_available_models() to Python and TypeScript SDKs#6460
juhuan wants to merge 1 commit into
QwenLM:mainfrom
juhuan:feat/sdk-get-available-models

Conversation

@juhuan

@juhuan juhuan commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Adds a new get_available_models control request that lets both SDKs query the list of models available for the current auth type at runtime. The CLI's SystemController handles the request by calling config.getAvailableModels() and returning each model's id, label, description, and isVision fields.

Changes by package

CLI (packages/cli):

  • nonInteractive/types.ts — added CLIControlGetAvailableModelsRequest type and included it in ControlRequestPayload
  • nonInteractive/control/ControlDispatcher.ts — routes get_available_models to SystemController
  • nonInteractive/control/controllers/systemController.ts — added handleGetAvailableModels handler that calls config.getAvailableModels(); added can_get_available_models capability to the initialize response

Python SDK (packages/sdk-python):

  • protocol.py — added CLIControlGetAvailableModelsRequest TypedDict and included it in ControlRequestPayload
  • query.py — added get_available_models() async method on Query

TypeScript SDK (packages/sdk-typescript):

  • types/protocol.ts — added GET_AVAILABLE_MODELS to ControlRequestType enum
  • query/Query.ts — added getAvailableModels() async method on Query

Why it's needed

Without a way to query available models, SDK users have no programmatic way to discover which models they can use or switch to. The CLI's /model interactive command already shows this list, but neither SDK exposed it. This method complements the existing set_model() / setModel() runtime method — users can now list available models and then switch to one.

Reviewer Test Plan

How to verify

Python SDK:

  1. cd packages/sdk-python && PYTHONPATH=src python3 -m pytest tests/unit/test_transport.py -v — 36 tests pass, including the new test_get_available_models_protocol_type

TypeScript SDK:

  1. cd packages/sdk-typescript && npx vitest run test/unit/Query.test.ts — 55 tests pass
  2. Confirm query.getAvailableModels() sends a control request with subtype get_available_models

CLI:

  1. cd packages/cli && npx vitest run src/nonInteractive/control/ControlDispatcher.test.ts — includes new test should route get_available_models request to system controller
  2. Note: this test may fail in some local environments due to a pre-existing vitest module resolution issue with the https package in packages/core/src/telemetry. This is unrelated to this PR.

Evidence (Before & After)

N/A — SDK method addition, no user-visible TUI change

Tested on

OS Status
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux

Environment

Unit tests only: Python 3.11 with pytest 9.1, Node.js 22 with vitest 1.6

Risk & Scope

  • Main risk or tradeoff: This adds a new control request subtype to the CLI's ControlDispatcher. If a SDK sends this request to an older CLI version that doesn't recognize get_available_models, the CLI will return an "Unknown control request subtype" error. This is expected and backward-compatible — the SDK should handle this gracefully (the method returns dict | None).
  • Not validated / out of scope: End-to-end test with a real CLI process. The handler uses config.getAvailableModels() which is already well-tested in the core package.
  • Breaking changes / migration notes: None. New method only, no changes to existing behavior.

Linked Issues

Related to #4158

中文说明

本 PR 做了什么

新增 get_available_models 控制请求,允许两个 SDK 在运行时查询当前认证类型下可用的模型列表。CLI 的 SystemController 通过调用 config.getAvailableModels() 处理请求,返回每个模型的 idlabeldescriptionisVision 字段。

为什么需要

SDK 用户此前无法通过编程方式查询可用模型列表。CLI 的 /model 交互命令已展示此列表,但 SDK 未暴露。该方法与已有的 set_model() / setModel() 运行时方法配合使用——用户可以先列出可用模型再切换。

风险与范围

  • 主要风险:向 CLI 的 ControlDispatcher 新增了控制请求子类型。如果 SDK 向不支持该子类型的旧版 CLI 发送请求,CLI 会返回"Unknown control request subtype"错误。这是预期的向后兼容行为。
  • 未验证:未进行真实 CLI 进程的端到端测试。handler 使用的 config.getAvailableModels() 已在 core 包中有充分测试。
  • 破坏性变更:无。仅新增方法,不改变现有行为。

Add a new control request `get_available_models` that returns the list
of models available for the current auth type. The CLI's SystemController
handles the request by calling config.getAvailableModels() and returning
id, label, description, and isVision for each model. Both SDKs expose this
as a runtime method on the Query class.
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: This is a real gap — SDK users currently have no programmatic way to discover available models. The set_model() / setModel() methods exist but there's no way to know what to pass them. Linked to #4158.

Direction: Clean alignment with the SDK's mission as a programmatic interface to the CLI. The /model command and set_model control request already exist; this is the natural complement. Claude Code has similar model discovery (/v1/models gateway discovery for the /model picker), so the area is relevant even though there's no exact SDK equivalent.

Size: Cross-package (CLI + Python SDK + TypeScript SDK) but small and focused. 70 production logic lines + 44 test lines. Well within bounds.

Approach: The implementation closely follows the existing get_context_usage pattern — same handler structure, same routing, same SDK method shape. Scope feels right for the goal. One observation: the response intentionally maps only id, label, description, isVision from AvailableModel, omitting fields like authType, contextWindowSize, and baseUrl. This seems deliberate (hiding internal implementation details from SDK consumers) but worth confirming that these fields aren't needed for any foreseeable SDK use case.

Moving on to code review and testing. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:这是一个真实的缺口——SDK 用户目前没有编程方式查询可用模型。set_model() / setModel() 方法已存在,但用户不知道该传什么值。已关联 #4158

方向:与 SDK 作为 CLI 编程接口的定位高度一致。/model 命令和 set_model 控制请求已存在,这是自然的补充。Claude Code 有类似的模型发现功能(/v1/models 网关发现),所以该领域是相关的,尽管没有完全对应的 SDK 等效。

规模:跨包(CLI + Python SDK + TypeScript SDK)但很小且聚焦。70 行生产代码 + 44 行测试。在合理范围内。

方案:实现紧密跟随已有的 get_context_usage 模式——相同的 handler 结构、路由、SDK 方法形态。范围对目标来说是合理的。一个观察:响应中只映射了 AvailableModelidlabeldescriptionisVision,省略了 authTypecontextWindowSizebaseUrl 等字段。这看起来是有意为之(对 SDK 消费者隐藏内部实现细节),但值得确认这些字段在可预见的 SDK 使用场景中不需要。

进入代码审查和测试 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

2a. Code Review

Independent proposal: To expose model discovery to SDKs, I'd add a get_available_models control request subtype, route it to SystemController, and have the handler call the existing config.getAvailableModels(). The response should include display-relevant fields (id, label, description, vision support) while omitting internal details (authType, baseUrl). SDK methods would be one-liners delegating to _send_control_request / sendControlRequest, mirroring existing methods like get_context_usage.

Comparison with the PR: The implementation matches this proposal exactly. Every file change follows the established get_context_usage pattern — same routing, same handler structure, same SDK method shape.

Correctness: Clean. The isVision fallback (m.isVision ?? m.capabilities?.vision ?? false) correctly handles all three cases in the AvailableModel type: explicit boolean, capability-based, or default false. The response intentionally omits internal fields (authType, contextWindowSize, baseUrl) — appropriate for SDK consumers who don't need implementation details.

No critical blockers. No AGENTS.md violations. The code is straightforward, minimal, and follows existing conventions.

2b. Testing

This is a pure SDK protocol addition — no TUI change, no CLI behavior change. tmux testing is not applicable here. Unit tests are the appropriate verification.

CLI — ControlDispatcher (37/37 pass ✅)

 ✓ src/nonInteractive/control/ControlDispatcher.test.ts (37 tests) 31ms

 ✓ ControlDispatcher > dispatch > should route get_available_models request to system controller

 Test Files  1 passed (1)
      Tests  37 passed (37)

TypeScript SDK — Query (55/55 pass ✅)

 ✓ test/unit/Query.test.ts (55 tests) 23673ms

 Test Files  1 passed (1)
      Tests  55 passed (55)

Python SDK — Transport (new test pass ✅, 4 pre-existing failures unrelated)

tests/unit/test_transport.py::test_get_available_models_protocol_type PASSED [100%]

=========================== short test summary info ============================
FAILED tests/unit/test_transport.py::test_transport_discards_stderr_when_debug_is_disabled - Failed: async def functions are not natively supported.
FAILED tests/unit/test_transport.py::test_transport_start_raises_after_close - ...
FAILED tests/unit/test_transport.py::test_read_messages_skips_malformed_json_lines - ...
FAILED tests/unit/test_transport.py::test_stderr_callback_exceptions_do_not_fail_transport - ...
=================== 4 failed, 9 passed, 5 warnings in 0.05s ====================

The 4 failures are pre-existing — they require pytest-asyncio which isn't installed in this environment. The new synchronous test passes.

Typecheck

$ npx tsc --noEmit -p packages/cli/tsconfig.json        # clean ✅
$ npx tsc --noEmit -p packages/sdk-typescript/tsconfig.json  # clean ✅
中文说明

2a. 代码审查

独立提案: 要将模型发现暴露给 SDK,我会添加 get_available_models 控制请求子类型,路由到 SystemController,handler 调用已有的 config.getAvailableModels()。响应应包含展示相关字段(id、label、description、vision 支持),省略内部细节(authType、baseUrl)。SDK 方法为单行委托到 _send_control_request / sendControlRequest,与 get_context_usage 等方法一致。

与 PR 对比: 实现完全匹配此提案。每个文件改动都遵循已有的 get_context_usage 模式——相同的路由、handler 结构、SDK 方法形态。

正确性: 无问题。isVision 回退逻辑(m.isVision ?? m.capabilities?.vision ?? false)正确处理了 AvailableModel 类型的三种情况:显式布尔值、基于 capability、或默认 false。响应有意省略了内部字段(authTypecontextWindowSizebaseUrl)——对不需要实现细节的 SDK 消费者来说是合理的。

无关键阻塞。无 AGENTS.md 违规。 代码简洁、最小,遵循已有约定。

2b. 测试

这是纯 SDK 协议添加——无 TUI 变更,无 CLI 行为变更。tmux 测试不适用。单元测试是正确的验证方式。

  • CLI ControlDispatcher: 37/37 通过 ✅
  • TypeScript SDK Query: 55/55 通过 ✅
  • Python SDK Transport: 新测试通过 ✅(4 个预先存在的异步测试失败与 PR 无关)
  • Typecheck: CLI 和 TypeScript SDK 均通过 ✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean, well-scoped SDK feature. The implementation follows the existing get_context_usage control request pattern in every detail — routing, handler structure, SDK method shape. All three test suites pass, typecheck is clean, and the diff contains exactly what's needed for the stated goal with nothing extra.

The problem is real: SDK users can call set_model() but have no way to discover what models are available. This closes that gap with a minimal, well-tested addition across three packages.

One observation for the maintainer's awareness: the response maps only four fields from AvailableModel (id, label, description, isVision), omitting authType, contextWindowSize, baseUrl, modalities, and others. This seems intentional (hiding internals from SDK consumers), but if any SDK use case might need these fields later, the response shape is easy to extend.

LGTM. ✅

中文说明

这是一个干净、范围合理的 SDK 功能。实现在每个细节上都遵循已有的 get_context_usage 控制请求模式——路由、handler 结构、SDK 方法形态。三个测试套件全部通过,typecheck 干净,diff 只包含目标所需的内容。

问题是真实的:SDK 用户可以调用 set_model() 但无法发现有哪些模型可用。这个 PR 通过在三个包中的最小化、良好测试的添加来弥补这一缺口。

一个供维护者注意的观察:响应只映射了 AvailableModel 的四个字段(idlabeldescriptionisVision),省略了 authTypecontextWindowSizebaseUrlmodalities 等。这看起来是有意为之(对 SDK 消费者隐藏内部细节),但如果后续有 SDK 使用场景需要这些字段,响应结构很容易扩展。

LGTM. ✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: CI still running.

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

💡 Suggestion: Consolidate SDK PRs

Hi @juhuan, thanks for the comprehensive SDK work! We noticed you have 15 open PRs that all modify the same core files (transport.py, types.py, queryOptionsSchema.ts, types.ts, ProcessTransport.ts, createQuery.ts) and were created on the same day.

The problem

  • Merge conflicts: Since all 15 PRs touch the same files, whichever merges first will cause conflicts in the remaining 14.
  • Review overhead: Reviewing 15 near-identical PRs separately is inefficient and risks fatigue.
  • CI cost: 15 separate CI runs for the same lint/typecheck passes.

Suggestion: regroup into 2 PRs

We recommend closing the current 15 PRs and reopening them as 2 consolidated PRs:

PR 1 — feat(sdk): expose transport and query options in both SDKs

Covers pure SDK-side option additions (~9 current PRs):

PR 2 — feat(sdk): add control request methods to both SDKs

Covers features that also involve CLI-side ControlDispatcher changes (~4 current PRs):

This keeps a reasonable separation of concerns while eliminating the merge-conflict chain and making review much more manageable.

/cc @juhuan

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Closing in favor of consolidated PRs (see suggestion comment above). Please reopen as 2 grouped PRs.

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.

3 participants