Skip to content

Commit f128f6d

Browse files
Merge pull request #191 from songguocola/feature/audio-update-0909
Feature/audio add Omni video compactness support and ASR runtime `input.context` updates via `continue-task`.
1 parent bcbe303 commit f128f6d

46 files changed

Lines changed: 1674 additions & 2106 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ else:
5252

5353
## API Key Authentication
5454

55-
The SDK uses API key for authentication. Please refer to [official documentation for alibabacloud china](https://www.alibabacloud.com/help/en/model-studio/) and [official documentation for alibabacloud international](https://www.alibabacloud.com/help/en/model-studio/) regarding how to obtain your api-key.
55+
The SDK uses API key for authentication. To obtain an API Key, see [How to get an API Key](https://help.aliyun.com/en/model-studio/get-api-key). Please refer to [official documentation for alibabacloud china](https://www.alibabacloud.com/help/en/model-studio/) and [official documentation for alibabacloud international](https://www.alibabacloud.com/help/en/model-studio/) regarding how to obtain your api-key.
5656

5757
### Using the API Key
5858

@@ -95,6 +95,7 @@ The SDK ships with an interactive AI assistant, **DashScope SDK Expert**, built
9595

9696
- Run `dashscope` with no arguments to start the assistant. On first run it offers to install the SDK Expert knowledge pack (per-domain quick-reference skills: text, multimodal, speech, retrieval, fine-tuning, agent, cli), so guidance comes from the SDK's public interfaces — parameters, outputs, error codes — without reading the source
9797
- Ask it instead of reading docs — e.g. `dashscope "how do I stream Generation output"` or `dashscope "CLI command to cancel a fine-tuning job"`. Type `/help` inside the assistant to list available commands (`/setup`, `/skill`, `/stats`, ...); classic SDK subcommands still work, and unrecognized commands are routed to the assistant
98+
- Full walkthrough: [DashScope SDK Expert guide](https://help.aliyun.com/en/model-studio/dashscope-sdk-expert)
9899

99100
## Supported Models
100101

‎README_zh.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ else:
5151

5252
## API Key 鉴权
5353

54-
SDK 使用 API Key 进行鉴权。获取 API Key 的方法请参考[阿里云百炼官方文档(国内站)](https://help.aliyun.com/zh/model-studio/)和[阿里云百炼官方文档(国际站)](https://www.alibabacloud.com/help/en/model-studio/)。
54+
SDK 使用 API Key 进行鉴权。获取 API Key 请参见[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key),或参考[阿里云百炼官方文档(国内站)](https://help.aliyun.com/zh/model-studio/)和[阿里云百炼官方文档(国际站)](https://www.alibabacloud.com/help/en/model-studio/)。
5555

5656
### 使用 API Key
5757

@@ -94,6 +94,7 @@ SDK 内置了交互式 AI 助手 **DashScope SDK Expert**,基于随包提供
9494

9595
- 直接运行 `dashscope`(不带参数)即可启动助手。首次运行时会提示安装 SDK Expert 知识包(按领域划分的速查技能:文本、多模态、语音、检索、微调、Agent、CLI),使助手的指导来自 SDK 的公开接口——参数、输出、错误码——而无需阅读源码
9696
- 直接提问代替翻文档——如 `dashscope "如何流式输出 Generation 结果"` 或 `dashscope "取消微调任务的 CLI 命令"`。在助手内输入 `/help` 可列出可用命令(`/setup`、`/skill`、`/stats` 等);经典 SDK 子命令依然可用,无法识别的命令会自动转给助手处理
97+
- 完整使用指南:[DashScope SDK Expert 文档](https://help.aliyun.com/zh/model-studio/dashscope-sdk-expert)
9798

9899
## 支持的模型
99100

‎dashscope/acli/agents/subagents.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Subagents are a subset of capabilities that function as autonomous workers
55
you delegate tasks to (vs. tool capabilities that the main agent calls).
66
Currently: local.subagent (built-in) + extension capabilities that act as
7-
remote agents (e.g., Coze workflows).
7+
remote agents (e.g., a hosted workflow engine).
88
99
The /subagents command provides:
1010
- list: show all discovered subagents with status

‎dashscope/acli/cli/examples.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,12 @@ def _copy_example_flat(src: Path, dst: Path, *, force: bool) -> bool:
256256
)
257257

258258
console.print(f"[green]✓ Example copied to: {acli_dir}[/green]")
259+
if src.name == "dashscope-sdk-expert":
260+
from dashscope.acli.cli.handlers_key import _GUIDE_DOC, _doc_locale
261+
262+
console.print(
263+
f"[dim]Guide: {_GUIDE_DOC.format(_doc_locale())}[/dim]",
264+
)
259265
if backup_dir is not None:
260266
console.print(
261267
f"[dim]Overwritten files backed up to: {backup_dir} "

‎dashscope/acli/cli/handlers_key.py‎

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616

1717
console = Console()
1818

19+
# Model Studio doc links for the no-key startup prompt; locale segment
20+
# comes from _doc_locale().
21+
_GET_API_KEY_DOC = "https://help.aliyun.com/{}/model-studio/get-api-key"
22+
_GUIDE_DOC = "https://help.aliyun.com/{}/model-studio/dashscope-sdk-expert"
23+
24+
25+
def _doc_locale() -> str:
26+
"""Pick the help-center locale from the process locale env vars."""
27+
import os
28+
29+
for var in ("LC_ALL", "LC_MESSAGES", "LANG"):
30+
if "zh" in (os.environ.get(var) or "").lower():
31+
return "zh"
32+
return "en"
33+
1934

2035
def all_key_targets(config: Config | None = None) -> dict[str, dict]:
2136
"""Merge KEY_TARGETS (built-in) with extension providers into one dict.
@@ -63,6 +78,26 @@ def _prompt_input(prompt: str, secret: bool = False) -> str:
6378
return ""
6479

6580

81+
def _print_no_key_prompt(config: Config, env_name: str) -> None:
82+
"""Present the missing-key notice, doc links, and setup menu."""
83+
console.print(
84+
f"\n[yellow]No API Key detected for " f"{config.provider}[/yellow]",
85+
)
86+
if config.provider.lower() == "tongyi":
87+
lang = _doc_locale()
88+
console.print(
89+
f"[dim]Get an API Key: {_GET_API_KEY_DOC.format(lang)}[/dim]",
90+
)
91+
console.print(f"[dim]Guide: {_GUIDE_DOC.format(lang)}[/dim]")
92+
console.print("Choose how to set it up:")
93+
if env_name:
94+
console.print(f" [1] Set env var {env_name} (exit and set)")
95+
else:
96+
console.print(" [1] Set corresponding env var (exit and set)")
97+
console.print(" [2] Enter API Key now")
98+
console.print(" [3] Set up later with /provider after startup")
99+
100+
66101
def ensure_provider_key(config: Config, agent) -> bool:
67102
"""If the active provider has no resolvable key, prompt the user.
68103
@@ -81,23 +116,27 @@ def ensure_provider_key(config: Config, agent) -> bool:
81116
ext = find_provider(config.provider)
82117
targets = all_key_targets(config)
83118
key_info = targets.get(config.provider)
119+
if ext is None and key_info is None:
120+
# Neither a built-in nor a loaded extension: this directory cannot
121+
# build that provider, so collecting a key is a dead end — and the
122+
# "<PROVIDER>_API_KEY" env var we would suggest is read by nothing.
123+
console.print(
124+
f"\n[yellow]Configured provider '{config.provider}' is not "
125+
"available here (no built-in or loaded extension by that "
126+
"name), so an API key alone will not make it work.[/yellow]",
127+
)
128+
console.print(
129+
"[dim]Starting anyway; run /provider to pick an available "
130+
"provider.[/dim]",
131+
)
132+
return True
133+
84134
if key_info:
85135
env_name = key_info.get("env") or ""
86-
elif ext is not None:
87-
env_name = ext.api_key_env or ""
88136
else:
89-
env_name = f"{config.provider.upper()}_API_KEY"
137+
env_name = ext.api_key_env or ""
90138

91-
console.print(
92-
f"\n[yellow]No API Key detected for " f"{config.provider}[/yellow]",
93-
)
94-
console.print("Choose how to set it up:")
95-
if env_name:
96-
console.print(f" [1] Set env var {env_name} (exit and set)")
97-
else:
98-
console.print(" [1] Set corresponding env var (exit and set)")
99-
console.print(" [2] Enter API Key now")
100-
console.print(" [3] Set up later with /provider after startup")
139+
_print_no_key_prompt(config, env_name)
101140
choice = input("\nChoose [1/2/3]: ").strip()
102141

103142
if choice == "1":
@@ -219,7 +258,7 @@ def _set_extension_provider_token(
219258
console.print("[dim]Cancelled[/dim]")
220259
return False
221260

222-
# Save to the provider's dynamic slot, e.g. ideatalk_api_key.
261+
# Save to the provider's dynamic slot, i.e. <name>_api_key.
223262
old_provider = config.provider
224263
try:
225264
config.provider = ext_prov.name

‎dashscope/acli/cli/handlers_provider.py‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,32 @@ def _provider_wizard(agent: Agent, config: Config) -> bool:
168168
for err in loaded.errors:
169169
console.print(f"[yellow]custom-extensions.toml: {err}[/yellow]")
170170

171-
# 1) Provider — Enter keeps the current one.
171+
# 1) Provider — Enter keeps the current one, but only when it is
172+
# loadable. A persisted extension provider whose custom-extensions.toml
173+
# is not present here is absent from `names`, so offering it as the
174+
# default turns a bare Enter into "Unknown provider; cancelled".
172175
names = list(PROVIDER_MODELS) + [
173176
p.name for p in loaded.providers if p.name not in PROVIDER_MODELS
174177
]
175-
provider = _numbered_pick("Available providers", names, config.provider)
178+
current = config.provider if config.provider in names else ""
179+
if config.provider and not current:
180+
console.print(
181+
f"[yellow]Configured provider '{config.provider}' is not "
182+
"available here (no built-in or loaded extension by that "
183+
"name), so Enter cannot keep it — pick one below.[/yellow]",
184+
)
185+
provider = _numbered_pick(
186+
"Available providers",
187+
names,
188+
current,
189+
custom_hint=(
190+
"Need one that is not listed? /dev provider add registers it "
191+
"in custom-extensions.toml"
192+
),
193+
)
194+
if not provider:
195+
console.print("[dim]No provider chosen; cancelled[/dim]")
196+
return True
176197
if provider not in names:
177198
console.print(f"[red]Unknown provider: {provider}; cancelled[/red]")
178199
return True

‎dashscope/acli/cli/startup.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ def _print_banner(config: Config | None = None) -> None:
156156
f"[dim]{', '.join(sdk_index)}[/dim]",
157157
)
158158

159+
# Scenario doc link (embedded mode only)
160+
guide_url = getattr(config, "_embedded_guide_url", "")
161+
if guide_url:
162+
console.print(f" [bold]Guide:[/bold] [dim]{guide_url}[/dim]")
163+
159164
console.print()
160165

161166
console.print(" [dim]Session: /help /clear /exit[/dim]")

‎dashscope/acli/config.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,8 +466,8 @@ def _load_global(self):
466466
key_field = f"{prov}_api_key"
467467
if key_field in data and not getattr(self, key_field):
468468
setattr(self, key_field, decrypt_value(str(data[key_field])))
469-
# Extension providers (ideatalk/deepseek/zhipu/...) may also store keys
470-
# as <name>_api_key in the global config file.
469+
# Extension providers may also store keys as <name>_api_key in
470+
# the global config file.
471471
for key, val in data.items():
472472
if (
473473
key.endswith("_api_key")
@@ -740,8 +740,7 @@ def _global_lines(self) -> list[str]:
740740
lines.append(
741741
f"{prov}_api_key = {toml_str(encrypt_value(key_val))}",
742742
)
743-
# Extension provider keys stored as <name>_api_key (e.g.
744-
# ideatalk_api_key)
743+
# Extension provider keys stored as <name>_api_key
745744
for attr in self.__dict__:
746745
if attr.endswith("_api_key") and attr not in built_in_key_fields:
747746
key_val = getattr(self, attr, "")

‎dashscope/acli/dev.py‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,14 @@ def _model_list(config: Config) -> None:
146146
> Wire a new LLM into acli's chat / stream / tool-call loop.
147147
> In most scenarios **no code is needed** — just fill in a TOML block.
148148
149-
acli ships only 3 protocol implementations; every provider (including
150-
built-ins tongyi/anthropic/openai/deepseek/zhipu/ideatalk/ollama) is
151-
configured via `custom-extensions.toml`:
149+
acli ships 3 protocol implementations and 3 built-in providers
150+
(tongyi / anthropic / openai), which need no TOML at all. Every other
151+
provider is configured via `custom-extensions.toml`:
152152
153153
| Protocol | Implementation | Use case |
154154
|-------------|---------------------|---------------------------------|
155155
| `openai` | `OpenAIProvider` | OpenAI-compatible endpoints |
156-
| | | (Moonshot/Yi/Step/Deepseek/ |
157-
| | | Zhipu/Ollama…) |
156+
| | | (any vendor, or local Ollama…) |
158157
| `anthropic` | `AnthropicProvider` | Anthropic Messages API (Claude |
159158
| | | / proxied endpoints) |
160159
| `dashscope` | `TongyiProvider` | DashScope OpenAI-compat |
@@ -168,13 +167,13 @@ def _model_list(config: Config) -> None:
168167
(global) or `./.acli/custom-extensions.toml` (workspace):
169168
170169
```toml
171-
# Moonshot / Kimi — OpenAI compatible
170+
# Any OpenAI-compatible endpoint
172171
[[providers]]
173-
name = "moonshot"
174-
base_url = "https://api.moonshot.cn/v1"
175-
api_key_env = "MOONSHOT_API_KEY"
176-
default_model = "kimi-k2"
177-
models = ["kimi-k1"]
172+
name = "my-llm"
173+
base_url = "https://llm.example.com/v1"
174+
api_key_env = "MY_LLM_API_KEY"
175+
default_model = "my-model"
176+
models = ["my-model", "my-model-lite"]
178177
protocol = "openai"
179178
180179
# Access Qwen via an Anthropic-protocol proxy
@@ -527,7 +526,7 @@ def _provider_add(config: Config) -> None:
527526
return
528527
api_key_enc = encrypt_for_toml(secret)
529528
else:
530-
api_key_env = _prompt("Env var name (e.g. MOONSHOT_API_KEY)")
529+
api_key_env = _prompt("Env var name (e.g. MY_LLM_API_KEY)")
531530
if not api_key_env:
532531
console.print("[red]Env var name must not be empty[/red]")
533532
return
@@ -1102,7 +1101,7 @@ def handle_dev_command(cmd: str, config: Config) -> None:
11021101
if len(parts) >= 5:
11031102
_model_add(config, parts[3], parts[4])
11041103
elif len(parts) == 4:
1105-
# Allow shorthand: /dev model add glm-image
1104+
# Allow shorthand: /dev model add qwen-image
11061105
model = parts[3]
11071106
provider = _infer_provider_from_model(model)
11081107
if provider is None:

0 commit comments

Comments
 (0)