mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
feat(tokenplan): 添加 Token Plan 相关命令
新增 `tokenplan add-member`、`tokenplan assign-seats` 和 `tokenplan create-key` 命令,支持管理 Token Plan 组织成员和 API 密钥。相关文档已更新,提供使用示例和参数说明。
This commit is contained in:
@@ -119,6 +119,12 @@ bl quota check # 查看当前用量 vs
|
||||
bl quota check --model qwen3.6-plus --period 5 # 查看最近 5 分钟用量
|
||||
bl quota request --model qwen3.6-plus --tpm 6000000 # 申请临时 TPM 提额
|
||||
bl quota history # 查看提额历史记录
|
||||
|
||||
# Token Plan 团队版管理(需 AK/SK,见下方认证说明)
|
||||
bl tokenplan seats # 查看订阅席位明细
|
||||
bl tokenplan add-member --account-name dev --org-id org_xxx
|
||||
bl tokenplan assign-seats --workspace-id ws_xxx --seat-type standard --account-id acc_xxx
|
||||
bl tokenplan create-key --account-id acc_xxx --workspace-id ws_xxx
|
||||
```
|
||||
|
||||
> 更多案例与使用场景:[阿里云百炼 CLI 官方主页](https://bailian.console.aliyun.com/cli?source_channel=cli_github&)
|
||||
@@ -148,9 +154,9 @@ bl text chat --api-key sk-xxxxx --message "你好"
|
||||
bl auth login --console
|
||||
```
|
||||
|
||||
### 阿里云 AK/SK(仅知识库检索)
|
||||
### 阿里云 AK/SK(知识库检索与 Token Plan)
|
||||
|
||||
`knowledge retrieve` 命令需要阿里云 AccessKey。前往 [RAM 控制台](https://ram.console.aliyun.com/manage/ak) 获取。
|
||||
`knowledge retrieve` 与 `tokenplan` 命令组需要阿里云 AccessKey。前往 [RAM 控制台](https://ram.console.aliyun.com/manage/ak) 获取。
|
||||
|
||||
> 建议:创建 RAM 子账号并授予最小权限,避免使用主账号 AK/SK。
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ import quotaRequest from "./quota/request.ts";
|
||||
import quotaHistory from "./quota/history.ts";
|
||||
import quotaCheck from "./quota/check.ts";
|
||||
import tokenplanSeats from "./tokenplan/seats.ts";
|
||||
import tokenplanCreateKey from "./tokenplan/create-key.ts";
|
||||
import tokenplanAssignSeats from "./tokenplan/assign-seats.ts";
|
||||
import tokenplanAddMember from "./tokenplan/add-member.ts";
|
||||
|
||||
/** Command registry map (no dependency on registry.ts — safe for build-time import). */
|
||||
export const commands: Record<string, Command> = {
|
||||
@@ -96,5 +99,8 @@ export const commands: Record<string, Command> = {
|
||||
"quota history": quotaHistory,
|
||||
"quota check": quotaCheck,
|
||||
"tokenplan seats": tokenplanSeats,
|
||||
"tokenplan create-key": tokenplanCreateKey,
|
||||
"tokenplan assign-seats": tokenplanAssignSeats,
|
||||
"tokenplan add-member": tokenplanAddMember,
|
||||
update: update,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import {
|
||||
defineCommand,
|
||||
buildCanonicalQuery,
|
||||
signRequest,
|
||||
modelStudioHost,
|
||||
detectOutputFormat,
|
||||
maskToken,
|
||||
trackingHeaders,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
type AddOrganizationMemberResponse,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import { padEnd } from "../../output/cjk-width.ts";
|
||||
|
||||
const API_VERSION = "2026-02-10";
|
||||
const API_ACTION = "AddOrganizationMember";
|
||||
const API_PATH = "/tokenplan/organization/member-additions";
|
||||
|
||||
const DEFAULT_ORG_ROLE = "ORG_MEMBER";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan add-member",
|
||||
description: "Add a member to a Token Plan organization",
|
||||
usage: "bl tokenplan add-member --account-name <name> --org-id <id> [flags]",
|
||||
options: [
|
||||
{ flag: "--account-name <name>", description: "Member display name", required: true },
|
||||
{ flag: "--org-id <id>", description: "Organization ID", required: true },
|
||||
{
|
||||
flag: "--org-role-code <code>",
|
||||
description: "Organization role: ORG_ADMIN or ORG_MEMBER (default: ORG_MEMBER)",
|
||||
},
|
||||
{
|
||||
flag: "--spec-type <type>",
|
||||
description: "Seat tier to assign on creation: standard, pro, or max",
|
||||
},
|
||||
{
|
||||
flag: "--caller-uac-account-id <id>",
|
||||
description: "Caller UAC account ID",
|
||||
},
|
||||
{
|
||||
flag: "--namespace-id <id>",
|
||||
description: "Product namespace ID (Token Plan default: namespace-1)",
|
||||
},
|
||||
{ flag: "--access-key-id <key>", description: "Alibaba Cloud Access Key ID (deprecated)" },
|
||||
{
|
||||
flag: "--access-key-secret <key>",
|
||||
description: "Alibaba Cloud Access Key Secret (deprecated)",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan add-member --account-name dev_user --org-id org_123",
|
||||
"bl tokenplan add-member --account-name admin_user --org-id org_123 --org-role-code ORG_ADMIN",
|
||||
"bl tokenplan add-member --account-name member1 --org-id org_123 --spec-type standard",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const accessKeyId = (flags.accessKeyId as string) || config.accessKeyId;
|
||||
const accessKeySecret = (flags.accessKeySecret as string) || config.accessKeySecret;
|
||||
|
||||
if (!accessKeyId || !accessKeySecret) {
|
||||
throw new BailianError(
|
||||
"No credentials found.\n" +
|
||||
"Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET.",
|
||||
ExitCode.AUTH,
|
||||
);
|
||||
}
|
||||
|
||||
const accountName = flags.accountName as string | undefined;
|
||||
const orgId = flags.orgId as string | undefined;
|
||||
if (!accountName) {
|
||||
throw new BailianError("Missing required argument --account-name.", ExitCode.USAGE);
|
||||
}
|
||||
if (!orgId) {
|
||||
throw new BailianError("Missing required argument --org-id.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags);
|
||||
const queryString = buildCanonicalQuery(queryParams);
|
||||
const host = modelStudioHost(config.region);
|
||||
const endpoint = `https://${host}${API_PATH}${queryString ? `?${queryString}` : ""}`;
|
||||
|
||||
if (config.dryRun) {
|
||||
emitResult({ endpoint, query: queryParams }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = signRequest({
|
||||
accessKeyId,
|
||||
accessKeySecret,
|
||||
action: API_ACTION,
|
||||
version: API_VERSION,
|
||||
body: "",
|
||||
host,
|
||||
pathname: API_PATH,
|
||||
method: "POST",
|
||||
queryString,
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`> POST ${endpoint}\n`);
|
||||
process.stderr.write(`> AK: ${maskToken(accessKeyId)}\n`);
|
||||
}
|
||||
|
||||
const timeoutMs = config.timeout * 1000;
|
||||
const res = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: { ...headers, ...trackingHeaders() },
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`< ${res.status} ${res.statusText}\n`);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as AddOrganizationMemberResponse;
|
||||
|
||||
if (!res.ok || data.Success === false) {
|
||||
throw new BailianError(
|
||||
`${data.Code || res.status} - ${data.Message || res.statusText}`,
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitTextMember(data);
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(flags: GlobalFlags): Record<string, string | string[] | undefined> {
|
||||
const params: Record<string, string | string[] | undefined> = {};
|
||||
|
||||
if (flags.accountName) params.AccountName = flags.accountName as string;
|
||||
if (flags.orgId) params.OrgId = flags.orgId as string;
|
||||
params.OrgRoleCode =
|
||||
typeof flags.orgRoleCode === "string" && flags.orgRoleCode.length > 0
|
||||
? flags.orgRoleCode
|
||||
: DEFAULT_ORG_ROLE;
|
||||
if (flags.specType) params.SpecType = flags.specType as string;
|
||||
if (flags.callerUacAccountId) params.CallerUacAccountId = flags.callerUacAccountId as string;
|
||||
if (flags.namespaceId) params.NamespaceId = flags.namespaceId as string;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function emitTextMember(data: AddOrganizationMemberResponse): void {
|
||||
const item = data.Data;
|
||||
if (!item) {
|
||||
emitBare("Member added.");
|
||||
return;
|
||||
}
|
||||
|
||||
emitBare(`${padEnd("AccountId", 14)} ${item.AccountId ?? "-"}`);
|
||||
emitBare(`${padEnd("SeatAssigned", 14)} ${String(item.SeatAssigned ?? "-")}`);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import {
|
||||
defineCommand,
|
||||
buildCanonicalQuery,
|
||||
signRequest,
|
||||
modelStudioHost,
|
||||
detectOutputFormat,
|
||||
maskToken,
|
||||
trackingHeaders,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
type BatchAssignSeatsResponse,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
|
||||
const API_VERSION = "2026-02-10";
|
||||
const API_ACTION = "BatchAssignSeats";
|
||||
const API_PATH = "/tokenplan/subscription/seat-assignments";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan assign-seats",
|
||||
description: "Batch assign Token Plan seats to members",
|
||||
usage:
|
||||
"bl tokenplan assign-seats --workspace-id <id> --seat-type <type> --account-id <id> [flags]",
|
||||
options: [
|
||||
{
|
||||
flag: "--workspace-id <id>",
|
||||
description: "Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id)",
|
||||
},
|
||||
{
|
||||
flag: "--seat-type <type>",
|
||||
description: "Seat tier: standard, pro, or max",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
flag: "--account-id <id>",
|
||||
description: "Target member account ID (repeatable)",
|
||||
type: "array",
|
||||
},
|
||||
{
|
||||
flag: "--caller-uac-account-id <id>",
|
||||
description: "Caller UAC account ID",
|
||||
},
|
||||
{
|
||||
flag: "--namespace-id <id>",
|
||||
description: "Product namespace ID (Token Plan default: namespace-1)",
|
||||
},
|
||||
{
|
||||
flag: "--locale <locale>",
|
||||
description: "Language: zh-CN or en-US",
|
||||
},
|
||||
{ flag: "--access-key-id <key>", description: "Alibaba Cloud Access Key ID (deprecated)" },
|
||||
{
|
||||
flag: "--access-key-secret <key>",
|
||||
description: "Alibaba Cloud Access Key Secret (deprecated)",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan assign-seats --workspace-id ws_456 --seat-type standard --account-id acc_123",
|
||||
"bl tokenplan assign-seats --workspace-id ws_456 --seat-type pro --account-id acc_1 --account-id acc_2",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const accessKeyId = (flags.accessKeyId as string) || config.accessKeyId;
|
||||
const accessKeySecret = (flags.accessKeySecret as string) || config.accessKeySecret;
|
||||
|
||||
if (!accessKeyId || !accessKeySecret) {
|
||||
throw new BailianError(
|
||||
"No credentials found.\n" +
|
||||
"Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET.",
|
||||
ExitCode.AUTH,
|
||||
);
|
||||
}
|
||||
|
||||
const workspaceId = (flags.workspaceId as string) || config.workspaceId;
|
||||
const seatType = flags.seatType as string | undefined;
|
||||
if (!workspaceId) {
|
||||
throw new BailianError(
|
||||
"Missing workspace ID.\n" +
|
||||
"Set via: --workspace-id flag, env: BAILIAN_WORKSPACE_ID, or config: bl config set workspace_id <id>",
|
||||
ExitCode.USAGE,
|
||||
);
|
||||
}
|
||||
if (!seatType) {
|
||||
throw new BailianError("Missing required argument --seat-type.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const accountIds = flags.accountId;
|
||||
const hasAccountIds =
|
||||
(Array.isArray(accountIds) && accountIds.length > 0) ||
|
||||
(typeof accountIds === "string" && accountIds.length > 0);
|
||||
if (!hasAccountIds) {
|
||||
throw new BailianError("Missing required argument --account-id.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags, workspaceId);
|
||||
const queryString = buildCanonicalQuery(queryParams);
|
||||
const host = modelStudioHost(config.region);
|
||||
const endpoint = `https://${host}${API_PATH}${queryString ? `?${queryString}` : ""}`;
|
||||
|
||||
if (config.dryRun) {
|
||||
emitResult({ endpoint, query: queryParams }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = signRequest({
|
||||
accessKeyId,
|
||||
accessKeySecret,
|
||||
action: API_ACTION,
|
||||
version: API_VERSION,
|
||||
body: "",
|
||||
host,
|
||||
pathname: API_PATH,
|
||||
method: "POST",
|
||||
queryString,
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`> POST ${endpoint}\n`);
|
||||
process.stderr.write(`> AK: ${maskToken(accessKeyId)}\n`);
|
||||
}
|
||||
|
||||
const timeoutMs = config.timeout * 1000;
|
||||
const res = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: { ...headers, ...trackingHeaders() },
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`< ${res.status} ${res.statusText}\n`);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as BatchAssignSeatsResponse;
|
||||
|
||||
if (!res.ok || data.Success === false) {
|
||||
throw new BailianError(
|
||||
`${data.Code || res.status} - ${data.Message || res.statusText}`,
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitBare("Seats assigned successfully.");
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(
|
||||
flags: GlobalFlags,
|
||||
workspaceId: string,
|
||||
): Record<string, string | string[] | undefined> {
|
||||
const params: Record<string, string | string[] | undefined> = {};
|
||||
|
||||
params.WorkspaceId = workspaceId;
|
||||
if (flags.seatType) params.SeatType = flags.seatType as string;
|
||||
if (flags.callerUacAccountId) params.CallerUacAccountId = flags.callerUacAccountId as string;
|
||||
if (flags.namespaceId) params.NamespaceId = flags.namespaceId as string;
|
||||
if (flags.locale) params.Locale = flags.locale as string;
|
||||
|
||||
const accountIds = flags.accountId as string | string[] | undefined;
|
||||
if (Array.isArray(accountIds) && accountIds.length > 0) {
|
||||
params.AccountIds = accountIds;
|
||||
} else if (typeof accountIds === "string" && accountIds.length > 0) {
|
||||
params.AccountIds = accountIds;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
defineCommand,
|
||||
buildCanonicalQuery,
|
||||
signRequest,
|
||||
modelStudioHost,
|
||||
detectOutputFormat,
|
||||
maskToken,
|
||||
trackingHeaders,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
type CreateTokenPlanKeyResponse,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import { padEnd } from "../../output/cjk-width.ts";
|
||||
|
||||
const API_VERSION = "2026-02-10";
|
||||
const API_ACTION = "CreateTokenPlanKey";
|
||||
const API_PATH = "/tokenplan/api-keys";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan create-key",
|
||||
description: "Create a Token Plan API key for a seat",
|
||||
usage: "bl tokenplan create-key --account-id <id> --workspace-id <id> [flags]",
|
||||
options: [
|
||||
{ flag: "--account-id <id>", description: "Target member account ID", required: true },
|
||||
{
|
||||
flag: "--workspace-id <id>",
|
||||
description: "Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id)",
|
||||
},
|
||||
{ flag: "--description <text>", description: "API key description" },
|
||||
{
|
||||
flag: "--caller-uac-account-id <id>",
|
||||
description: "Caller UAC account ID",
|
||||
},
|
||||
{
|
||||
flag: "--namespace-id <id>",
|
||||
description: "Product namespace ID (Token Plan default: namespace-1)",
|
||||
},
|
||||
{ flag: "--access-key-id <key>", description: "Alibaba Cloud Access Key ID (deprecated)" },
|
||||
{
|
||||
flag: "--access-key-secret <key>",
|
||||
description: "Alibaba Cloud Access Key Secret (deprecated)",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan create-key --account-id acc_123 --workspace-id ws_456",
|
||||
"bl tokenplan create-key --account-id acc_123 --workspace-id ws_456 --description 'Dev key'",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const accessKeyId = (flags.accessKeyId as string) || config.accessKeyId;
|
||||
const accessKeySecret = (flags.accessKeySecret as string) || config.accessKeySecret;
|
||||
|
||||
if (!accessKeyId || !accessKeySecret) {
|
||||
throw new BailianError(
|
||||
"No credentials found.\n" +
|
||||
"Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET.",
|
||||
ExitCode.AUTH,
|
||||
);
|
||||
}
|
||||
|
||||
const accountId = flags.accountId as string | undefined;
|
||||
const workspaceId = (flags.workspaceId as string) || config.workspaceId;
|
||||
if (!accountId) {
|
||||
throw new BailianError("Missing required argument --account-id.", ExitCode.USAGE);
|
||||
}
|
||||
if (!workspaceId) {
|
||||
throw new BailianError(
|
||||
"Missing workspace ID.\n" +
|
||||
"Set via: --workspace-id flag, env: BAILIAN_WORKSPACE_ID, or config: bl config set workspace_id <id>",
|
||||
ExitCode.USAGE,
|
||||
);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags, { accountId, workspaceId });
|
||||
const queryString = buildCanonicalQuery(queryParams);
|
||||
const host = modelStudioHost(config.region);
|
||||
const endpoint = `https://${host}${API_PATH}${queryString ? `?${queryString}` : ""}`;
|
||||
|
||||
if (config.dryRun) {
|
||||
emitResult({ endpoint, query: queryParams }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = signRequest({
|
||||
accessKeyId,
|
||||
accessKeySecret,
|
||||
action: API_ACTION,
|
||||
version: API_VERSION,
|
||||
body: "",
|
||||
host,
|
||||
pathname: API_PATH,
|
||||
method: "POST",
|
||||
queryString,
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`> POST ${endpoint}\n`);
|
||||
process.stderr.write(`> AK: ${maskToken(accessKeyId)}\n`);
|
||||
}
|
||||
|
||||
const timeoutMs = config.timeout * 1000;
|
||||
const res = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: { ...headers, ...trackingHeaders() },
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`< ${res.status} ${res.statusText}\n`);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as CreateTokenPlanKeyResponse;
|
||||
|
||||
if (!res.ok || data.Success === false) {
|
||||
throw new BailianError(
|
||||
`${data.Code || res.status} - ${data.Message || res.statusText}`,
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitTextKey(data);
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(
|
||||
flags: GlobalFlags,
|
||||
resolved: { accountId: string; workspaceId: string },
|
||||
): Record<string, string | string[] | undefined> {
|
||||
const params: Record<string, string | string[] | undefined> = {};
|
||||
|
||||
params.AccountId = resolved.accountId;
|
||||
params.WorkspaceId = resolved.workspaceId;
|
||||
if (flags.description) params.Description = flags.description as string;
|
||||
if (flags.callerUacAccountId) params.CallerUacAccountId = flags.callerUacAccountId as string;
|
||||
if (flags.namespaceId) params.NamespaceId = flags.namespaceId as string;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function emitTextKey(data: CreateTokenPlanKeyResponse): void {
|
||||
const item = data.Data;
|
||||
if (!item) {
|
||||
emitBare("API key created.");
|
||||
return;
|
||||
}
|
||||
|
||||
emitBare(`${padEnd("ApiKeyId", 14)} ${item.ApiKeyId ?? "-"}`);
|
||||
emitBare(`${padEnd("MaskedApiKey", 14)} ${item.MaskedApiKey ?? "-"}`);
|
||||
if (item.Description) {
|
||||
emitBare(`${padEnd("Description", 14)} ${item.Description}`);
|
||||
}
|
||||
if (item.PlainApiKey) {
|
||||
emitBare("");
|
||||
emitBare(`PlainApiKey (shown once): ${item.PlainApiKey}`);
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,9 @@ const NO_AUTH_SETUP = [
|
||||
["quota", "history"],
|
||||
["quota", "check"],
|
||||
["tokenplan", "seats"],
|
||||
["tokenplan", "create-key"],
|
||||
["tokenplan", "assign-seats"],
|
||||
["tokenplan", "add-member"],
|
||||
];
|
||||
|
||||
async function main() {
|
||||
|
||||
@@ -7,12 +7,28 @@ interface DryRunBody {
|
||||
query?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
describe("e2e: tokenplan seats", () => {
|
||||
const noCredsEnv = {
|
||||
DASHSCOPE_API_KEY: undefined,
|
||||
DASHSCOPE_ACCESS_TOKEN: undefined,
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID: undefined,
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET: undefined,
|
||||
BAILIAN_CONFIG_DIR: tmpdir(),
|
||||
};
|
||||
|
||||
const fakeAkEnv = {
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID: "LTAI-fake",
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET: "fake-secret",
|
||||
};
|
||||
|
||||
describe("e2e: tokenplan", () => {
|
||||
test("tokenplan 分组展示子命令帮助且成功退出", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(["tokenplan"]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const out = `${stdout}\n${stderr}`;
|
||||
expect(out).toMatch(/tokenplan|seats/i);
|
||||
expect(out).toMatch(/create-key/i);
|
||||
expect(out).toMatch(/assign-seats/i);
|
||||
expect(out).toMatch(/add-member/i);
|
||||
});
|
||||
|
||||
test("tokenplan seats --help 正常退出", async () => {
|
||||
@@ -24,27 +40,195 @@ describe("e2e: tokenplan seats", () => {
|
||||
expect(stderr).toMatch(/--status/i);
|
||||
expect(stderr).toMatch(/--query-assigned/i);
|
||||
});
|
||||
|
||||
test("tokenplan create-key --help 正常退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(["tokenplan", "create-key", "--help"]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
expect(stderr).toMatch(/--account-id/i);
|
||||
expect(stderr).toMatch(/--workspace-id/i);
|
||||
});
|
||||
|
||||
test("tokenplan assign-seats --help 正常退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(["tokenplan", "assign-seats", "--help"]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
expect(stderr).toMatch(/--workspace-id/i);
|
||||
expect(stderr).toMatch(/--seat-type/i);
|
||||
expect(stderr).toMatch(/--account-id/i);
|
||||
});
|
||||
|
||||
test("tokenplan add-member --help 正常退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(["tokenplan", "add-member", "--help"]);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
expect(stderr).toMatch(/--account-name/i);
|
||||
expect(stderr).toMatch(/--org-id/i);
|
||||
expect(stderr).toMatch(/--org-role-code/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("e2e: tokenplan seats errors", () => {
|
||||
test("无任何凭证时提示 No credentials found 并非零退出", async () => {
|
||||
describe("e2e: tokenplan errors", () => {
|
||||
test("seats 无任何凭证时提示 No credentials found 并非零退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(
|
||||
["tokenplan", "seats", "--non-interactive", "--output", "json"],
|
||||
{
|
||||
DASHSCOPE_API_KEY: undefined,
|
||||
DASHSCOPE_ACCESS_TOKEN: undefined,
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID: undefined,
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET: undefined,
|
||||
BAILIAN_CONFIG_DIR: tmpdir(),
|
||||
},
|
||||
noCredsEnv,
|
||||
);
|
||||
expect(exitCode).not.toBe(0);
|
||||
expect(stderr).toMatch(/no credentials found/i);
|
||||
});
|
||||
|
||||
test("create-key 无任何凭证时提示 No credentials found 并非零退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"create-key",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--workspace-id",
|
||||
"ws_1",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
noCredsEnv,
|
||||
);
|
||||
expect(exitCode).not.toBe(0);
|
||||
expect(stderr).toMatch(/no credentials found/i);
|
||||
});
|
||||
|
||||
test("assign-seats 无任何凭证时提示 No credentials found 并非零退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"assign-seats",
|
||||
"--workspace-id",
|
||||
"ws_1",
|
||||
"--seat-type",
|
||||
"standard",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
noCredsEnv,
|
||||
);
|
||||
expect(exitCode).not.toBe(0);
|
||||
expect(stderr).toMatch(/no credentials found/i);
|
||||
});
|
||||
|
||||
test("add-member 无任何凭证时提示 No credentials found 并非零退出", async () => {
|
||||
const { stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"add-member",
|
||||
"--account-name",
|
||||
"user1",
|
||||
"--org-id",
|
||||
"org_1",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
noCredsEnv,
|
||||
);
|
||||
expect(exitCode).not.toBe(0);
|
||||
expect(stderr).toMatch(/no credentials found/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("e2e: tokenplan seats dry-run", () => {
|
||||
test("--dry-run 输出 endpoint 和 query 参数", async () => {
|
||||
describe.skipIf(!isTokenPlanAkSkReady())("e2e: tokenplan missing args", () => {
|
||||
test("create-key 缺少 --account-id 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"create-key",
|
||||
"--workspace-id",
|
||||
"ws_1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--account-id|Missing required argument/i);
|
||||
});
|
||||
|
||||
test("create-key 缺少 --workspace-id 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"create-key",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/workspace-id|Missing workspace ID/i);
|
||||
});
|
||||
|
||||
test("assign-seats 缺少 --workspace-id 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"assign-seats",
|
||||
"--seat-type",
|
||||
"standard",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/workspace-id|Missing workspace ID/i);
|
||||
});
|
||||
|
||||
test("assign-seats 缺少 --seat-type 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"assign-seats",
|
||||
"--workspace-id",
|
||||
"ws_1",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--seat-type|Missing required argument/i);
|
||||
});
|
||||
|
||||
test("assign-seats 缺少 account id 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"assign-seats",
|
||||
"--workspace-id",
|
||||
"ws_1",
|
||||
"--seat-type",
|
||||
"standard",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--account-id|Missing required argument/i);
|
||||
});
|
||||
|
||||
test("add-member 缺少 --account-name 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"add-member",
|
||||
"--org-id",
|
||||
"org_1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--account-name|Missing required argument/i);
|
||||
});
|
||||
|
||||
test("add-member 缺少 --org-id 时退出为用法错误 (2)", async () => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"tokenplan",
|
||||
"add-member",
|
||||
"--account-name",
|
||||
"user1",
|
||||
"--non-interactive",
|
||||
]);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/--org-id|Missing required argument/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("e2e: tokenplan dry-run", () => {
|
||||
test("seats --dry-run 输出 endpoint 和 query 参数", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
@@ -62,10 +246,7 @@ describe("e2e: tokenplan seats dry-run", () => {
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
{
|
||||
ALIBABA_CLOUD_ACCESS_KEY_ID: "LTAI-fake",
|
||||
ALIBABA_CLOUD_ACCESS_KEY_SECRET: "fake-secret",
|
||||
},
|
||||
fakeAkEnv,
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
@@ -75,6 +256,106 @@ describe("e2e: tokenplan seats dry-run", () => {
|
||||
expect(data.query?.QueryAssigned).toBe("true");
|
||||
expect(data.query?.StatusList).toEqual(["NORMAL"]);
|
||||
});
|
||||
|
||||
test("create-key --dry-run 从 BAILIAN_WORKSPACE_ID 读取 workspace", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"create-key",
|
||||
"--dry-run",
|
||||
"--account-id",
|
||||
"acc_123",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
{ ...fakeAkEnv, BAILIAN_WORKSPACE_ID: "ws-from-env" },
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.query?.WorkspaceId).toBe("ws-from-env");
|
||||
});
|
||||
|
||||
test("create-key --dry-run 输出 endpoint 和 query 参数", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"create-key",
|
||||
"--dry-run",
|
||||
"--account-id",
|
||||
"acc_123",
|
||||
"--workspace-id",
|
||||
"ws_456",
|
||||
"--description",
|
||||
"test key",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
fakeAkEnv,
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.endpoint).toMatch(/\/tokenplan\/api-keys/);
|
||||
expect(data.query?.AccountId).toBe("acc_123");
|
||||
expect(data.query?.WorkspaceId).toBe("ws_456");
|
||||
expect(data.query?.Description).toBe("test key");
|
||||
});
|
||||
|
||||
test("assign-seats --dry-run 输出 endpoint 和 query 参数", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"assign-seats",
|
||||
"--dry-run",
|
||||
"--workspace-id",
|
||||
"ws_456",
|
||||
"--seat-type",
|
||||
"standard",
|
||||
"--account-id",
|
||||
"acc_1",
|
||||
"--account-id",
|
||||
"acc_2",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
fakeAkEnv,
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.endpoint).toMatch(/\/tokenplan\/subscription\/seat-assignments/);
|
||||
expect(data.query?.WorkspaceId).toBe("ws_456");
|
||||
expect(data.query?.SeatType).toBe("standard");
|
||||
expect(data.query?.AccountIds).toEqual(["acc_1", "acc_2"]);
|
||||
});
|
||||
|
||||
test("add-member --dry-run 输出 endpoint 和 query 参数", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCli(
|
||||
[
|
||||
"tokenplan",
|
||||
"add-member",
|
||||
"--dry-run",
|
||||
"--account-name",
|
||||
"dev_user",
|
||||
"--org-id",
|
||||
"org_123",
|
||||
"--spec-type",
|
||||
"standard",
|
||||
"--non-interactive",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
fakeAkEnv,
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.endpoint).toMatch(/\/tokenplan\/organization\/member-additions/);
|
||||
expect(data.query?.AccountName).toBe("dev_user");
|
||||
expect(data.query?.OrgId).toBe("org_123");
|
||||
expect(data.query?.OrgRoleCode).toBe("ORG_MEMBER");
|
||||
expect(data.query?.SpecType).toBe("standard");
|
||||
});
|
||||
});
|
||||
|
||||
describe.skipIf(!isTokenPlanAkSkReady())("e2e: tokenplan seats(AK/SK)", () => {
|
||||
|
||||
@@ -455,6 +455,38 @@ export interface GetSubscriptionSeatDetailsResponse {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateTokenPlanKeyResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
Data?: {
|
||||
ApiKeyId?: string;
|
||||
PlainApiKey?: string;
|
||||
MaskedApiKey?: string;
|
||||
Description?: string;
|
||||
CreatedAt?: string;
|
||||
SourceId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BatchAssignSeatsResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
}
|
||||
|
||||
export interface AddOrganizationMemberResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
RequestId?: string;
|
||||
HttpStatusCode?: number;
|
||||
Data?: {
|
||||
AccountId?: string;
|
||||
SeatAssigned?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// ---- Speech Synthesis / TTS (DashScope) ----
|
||||
|
||||
export interface DashScopeTTSRequest {
|
||||
|
||||
@@ -8,55 +8,58 @@ Use this index for the full quick index and global flags.
|
||||
|
||||
## Quick index
|
||||
|
||||
| Command | Description | Detail |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| `bl advisor recommend` | Recommend the best models for your use case (intent analysis → candidate recall → LLM ranking) | [advisor.md](advisor.md) |
|
||||
| `bl app call` | Call a Bailian application (agent or workflow) | [app.md](app.md) |
|
||||
| `bl app list` | List Bailian applications | [app.md](app.md) |
|
||||
| `bl auth login` | Authenticate with API key or console browser login (credentials can coexist) | [auth.md](auth.md) |
|
||||
| `bl auth logout` | Clear stored credentials | [auth.md](auth.md) |
|
||||
| `bl auth status` | Show current authentication state | [auth.md](auth.md) |
|
||||
| `bl config export-schema` | Export all (or one) CLI command(s) as Anthropic/OpenAI-compatible JSON tool schemas | [config.md](config.md) |
|
||||
| `bl config set` | Set a config value | [config.md](config.md) |
|
||||
| `bl config show` | Display current configuration | [config.md](config.md) |
|
||||
| `bl console call` | Call a Bailian console API via the CLI gateway | [console.md](console.md) |
|
||||
| `bl file upload` | Upload a local file to DashScope temporary storage (48h) | [file.md](file.md) |
|
||||
| `bl image edit` | Edit an existing image with text instructions (Qwen-Image) | [image.md](image.md) |
|
||||
| `bl image generate` | Generate images (Qwen-Image / wan2.x) | [image.md](image.md) |
|
||||
| `bl knowledge retrieve` | Retrieve from a Bailian knowledge base | [knowledge.md](knowledge.md) |
|
||||
| `bl mcp call` | Call a tool on an MCP server (tools/call) | [mcp.md](mcp.md) |
|
||||
| `bl mcp list` | List MCP servers activated under your Bailian account | [mcp.md](mcp.md) |
|
||||
| `bl mcp tools` | List tools exposed by an MCP server (tools/list) | [mcp.md](mcp.md) |
|
||||
| `bl memory add` | Add memory from messages or custom content | [memory.md](memory.md) |
|
||||
| `bl memory delete` | Delete a memory node | [memory.md](memory.md) |
|
||||
| `bl memory list` | List memory nodes for a user | [memory.md](memory.md) |
|
||||
| `bl memory profile create` | Create a user profile schema for memory profiling | [memory.md](memory.md) |
|
||||
| `bl memory profile get` | Get user profile by schema ID and user ID | [memory.md](memory.md) |
|
||||
| `bl memory search` | Search memory nodes by query or messages | [memory.md](memory.md) |
|
||||
| `bl memory update` | Update a memory node content | [memory.md](memory.md) |
|
||||
| `bl omni` | Multimodal chat with text + audio output (Qwen-Omni) | [omni.md](omni.md) |
|
||||
| `bl pipeline run` | Run a pipeline workflow definition | [pipeline.md](pipeline.md) |
|
||||
| `bl pipeline validate` | Validate a pipeline definition without executing | [pipeline.md](pipeline.md) |
|
||||
| `bl quota check` | Check current usage against rate limits | [quota.md](quota.md) |
|
||||
| `bl quota history` | View quota change history | [quota.md](quota.md) |
|
||||
| `bl quota list` | View model RPM/TPM rate limits | [quota.md](quota.md) |
|
||||
| `bl quota request` | Request a temporary quota increase | [quota.md](quota.md) |
|
||||
| `bl search web` | Search the web using DashScope MCP WebSearch service | [search.md](search.md) |
|
||||
| `bl speech recognize` | Recognize speech from audio files (FunAudio-ASR) | [speech.md](speech.md) |
|
||||
| `bl speech synthesize` | Synthesize speech from text (CosyVoice TTS) | [speech.md](speech.md) |
|
||||
| `bl text chat` | Send a chat completion (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details | [tokenplan.md](tokenplan.md) |
|
||||
| `bl update` | Update bl to the latest version | [update.md](update.md) |
|
||||
| `bl usage free` | Query free-tier quota for models (all models if --model is omitted) | [usage.md](usage.md) |
|
||||
| `bl usage freetier` | Enable or disable auto-stop for free-tier models. Enables by default; use --off to disable | [usage.md](usage.md) |
|
||||
| `bl usage stats` | Query model usage statistics | [usage.md](usage.md) |
|
||||
| `bl video download` | Download a completed video by task ID | [video.md](video.md) |
|
||||
| `bl video edit` | Edit a video with happyhorse-1.0-video-edit (style transfer, object replacement, etc.) | [video.md](video.md) |
|
||||
| `bl video generate` | Generate a video from text or image (happyhorse-1.0-t2v / happyhorse-1.0-i2v / wan2.6-t2v) | [video.md](video.md) |
|
||||
| `bl video ref` | Reference-to-video generation (happyhorse-1.0-r2v / wan2.6-r2v): multi-subject, multi-shot with voice | [video.md](video.md) |
|
||||
| `bl video task get` | Query async task status | [video.md](video.md) |
|
||||
| `bl vision describe` | Describe an image or video using Qwen-VL | [vision.md](vision.md) |
|
||||
| `bl workspace list` | List all workspaces | [workspace.md](workspace.md) |
|
||||
| Command | Description | Detail |
|
||||
| --------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| `bl advisor recommend` | Recommend the best models for your use case (intent analysis → candidate recall → LLM ranking) | [advisor.md](advisor.md) |
|
||||
| `bl app call` | Call a Bailian application (agent or workflow) | [app.md](app.md) |
|
||||
| `bl app list` | List Bailian applications | [app.md](app.md) |
|
||||
| `bl auth login` | Authenticate with API key or console browser login (credentials can coexist) | [auth.md](auth.md) |
|
||||
| `bl auth logout` | Clear stored credentials | [auth.md](auth.md) |
|
||||
| `bl auth status` | Show current authentication state | [auth.md](auth.md) |
|
||||
| `bl config export-schema` | Export all (or one) CLI command(s) as Anthropic/OpenAI-compatible JSON tool schemas | [config.md](config.md) |
|
||||
| `bl config set` | Set a config value | [config.md](config.md) |
|
||||
| `bl config show` | Display current configuration | [config.md](config.md) |
|
||||
| `bl console call` | Call a Bailian console API via the CLI gateway | [console.md](console.md) |
|
||||
| `bl file upload` | Upload a local file to DashScope temporary storage (48h) | [file.md](file.md) |
|
||||
| `bl image edit` | Edit an existing image with text instructions (Qwen-Image) | [image.md](image.md) |
|
||||
| `bl image generate` | Generate images (Qwen-Image / wan2.x) | [image.md](image.md) |
|
||||
| `bl knowledge retrieve` | Retrieve from a Bailian knowledge base | [knowledge.md](knowledge.md) |
|
||||
| `bl mcp call` | Call a tool on an MCP server (tools/call) | [mcp.md](mcp.md) |
|
||||
| `bl mcp list` | List MCP servers activated under your Bailian account | [mcp.md](mcp.md) |
|
||||
| `bl mcp tools` | List tools exposed by an MCP server (tools/list) | [mcp.md](mcp.md) |
|
||||
| `bl memory add` | Add memory from messages or custom content | [memory.md](memory.md) |
|
||||
| `bl memory delete` | Delete a memory node | [memory.md](memory.md) |
|
||||
| `bl memory list` | List memory nodes for a user | [memory.md](memory.md) |
|
||||
| `bl memory profile create` | Create a user profile schema for memory profiling | [memory.md](memory.md) |
|
||||
| `bl memory profile get` | Get user profile by schema ID and user ID | [memory.md](memory.md) |
|
||||
| `bl memory search` | Search memory nodes by query or messages | [memory.md](memory.md) |
|
||||
| `bl memory update` | Update a memory node content | [memory.md](memory.md) |
|
||||
| `bl omni` | Multimodal chat with text + audio output (Qwen-Omni) | [omni.md](omni.md) |
|
||||
| `bl pipeline run` | Run a pipeline workflow definition | [pipeline.md](pipeline.md) |
|
||||
| `bl pipeline validate` | Validate a pipeline definition without executing | [pipeline.md](pipeline.md) |
|
||||
| `bl quota check` | Check current usage against rate limits | [quota.md](quota.md) |
|
||||
| `bl quota history` | View quota change history | [quota.md](quota.md) |
|
||||
| `bl quota list` | View model RPM/TPM rate limits | [quota.md](quota.md) |
|
||||
| `bl quota request` | Request a temporary quota increase | [quota.md](quota.md) |
|
||||
| `bl search web` | Search the web using DashScope MCP WebSearch service | [search.md](search.md) |
|
||||
| `bl speech recognize` | Recognize speech from audio files (FunAudio-ASR) | [speech.md](speech.md) |
|
||||
| `bl speech synthesize` | Synthesize speech from text (CosyVoice TTS) | [speech.md](speech.md) |
|
||||
| `bl text chat` | Send a chat completion (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl tokenplan add-member` | Add a member to a Token Plan organization | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan assign-seats` | Batch assign Token Plan seats to members | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan create-key` | Create a Token Plan API key for a seat | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details | [tokenplan.md](tokenplan.md) |
|
||||
| `bl update` | Update bl to the latest version | [update.md](update.md) |
|
||||
| `bl usage free` | Query free-tier quota for models (all models if --model is omitted) | [usage.md](usage.md) |
|
||||
| `bl usage freetier` | Enable or disable auto-stop for free-tier models. Enables by default; use --off to disable | [usage.md](usage.md) |
|
||||
| `bl usage stats` | Query model usage statistics | [usage.md](usage.md) |
|
||||
| `bl video download` | Download a completed video by task ID | [video.md](video.md) |
|
||||
| `bl video edit` | Edit a video with happyhorse-1.0-video-edit (style transfer, object replacement, etc.) | [video.md](video.md) |
|
||||
| `bl video generate` | Generate a video from text or image (happyhorse-1.0-t2v / happyhorse-1.0-i2v / wan2.6-t2v) | [video.md](video.md) |
|
||||
| `bl video ref` | Reference-to-video generation (happyhorse-1.0-r2v / wan2.6-r2v): multi-subject, multi-shot with voice | [video.md](video.md) |
|
||||
| `bl video task get` | Query async task status | [video.md](video.md) |
|
||||
| `bl vision describe` | Describe an image or video using Qwen-VL | [vision.md](vision.md) |
|
||||
| `bl workspace list` | List all workspaces | [workspace.md](workspace.md) |
|
||||
|
||||
## By group
|
||||
|
||||
@@ -78,7 +81,7 @@ Use this index for the full quick index and global flags.
|
||||
| `search` | `web` | [search.md](search.md) |
|
||||
| `speech` | `recognize`, `synthesize` | [speech.md](speech.md) |
|
||||
| `text` | `chat` | [text.md](text.md) |
|
||||
| `tokenplan` | `seats` | [tokenplan.md](tokenplan.md) |
|
||||
| `tokenplan` | `add-member`, `assign-seats`, `create-key`, `seats` | [tokenplan.md](tokenplan.md) |
|
||||
| `update` | `(root)` | [update.md](update.md) |
|
||||
| `usage` | `free`, `freetier`, `stats` | [usage.md](usage.md) |
|
||||
| `video` | `download`, `edit`, `generate`, `ref`, `task get` | [video.md](video.md) |
|
||||
|
||||
@@ -7,12 +7,111 @@ Index: [index.md](index.md)
|
||||
|
||||
## Commands in this group
|
||||
|
||||
| Command | Description |
|
||||
| -------------------- | ----------------------------------------- |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details |
|
||||
| Command | Description |
|
||||
| --------------------------- | ----------------------------------------- |
|
||||
| `bl tokenplan add-member` | Add a member to a Token Plan organization |
|
||||
| `bl tokenplan assign-seats` | Batch assign Token Plan seats to members |
|
||||
| `bl tokenplan create-key` | Create a Token Plan API key for a seat |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details |
|
||||
|
||||
## Command details
|
||||
|
||||
### `bl tokenplan add-member`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | --------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan add-member` |
|
||||
| **Description** | Add a member to a Token Plan organization |
|
||||
| **Usage** | `bl tokenplan add-member --account-name <name> --org-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ---------------------------------------------------------------- |
|
||||
| `--account-name <name>` | string | yes | Member display name |
|
||||
| `--org-id <id>` | string | yes | Organization ID |
|
||||
| `--org-role-code <code>` | string | no | Organization role: ORG_ADMIN or ORG_MEMBER (default: ORG_MEMBER) |
|
||||
| `--spec-type <type>` | string | no | Seat tier to assign on creation: standard, pro, or max |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name dev_user --org-id org_123
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name admin_user --org-id org_123 --org-role-code ORG_ADMIN
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name member1 --org-id org_123 --spec-type standard
|
||||
```
|
||||
|
||||
### `bl tokenplan assign-seats`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | -------------------------------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan assign-seats` |
|
||||
| **Description** | Batch assign Token Plan seats to members |
|
||||
| **Usage** | `bl tokenplan assign-seats --workspace-id <id> --seat-type <type> --account-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | -------------------------------------------------------------- |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id) |
|
||||
| `--seat-type <type>` | string | yes | Seat tier: standard, pro, or max |
|
||||
| `--account-id <id>` | array | no | Target member account ID (repeatable) |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--locale <locale>` | string | no | Language: zh-CN or en-US |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan assign-seats --workspace-id ws_456 --seat-type standard --account-id acc_123
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan assign-seats --workspace-id ws_456 --seat-type pro --account-id acc_1 --account-id acc_2
|
||||
```
|
||||
|
||||
### `bl tokenplan create-key`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | ----------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan create-key` |
|
||||
| **Description** | Create a Token Plan API key for a seat |
|
||||
| **Usage** | `bl tokenplan create-key --account-id <id> --workspace-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | -------------------------------------------------------------- |
|
||||
| `--account-id <id>` | string | yes | Target member account ID |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id) |
|
||||
| `--description <text>` | string | no | API key description |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan create-key --account-id acc_123 --workspace-id ws_456
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan create-key --account-id acc_123 --workspace-id ws_456 --description 'Dev key'
|
||||
```
|
||||
|
||||
### `bl tokenplan seats`
|
||||
|
||||
| Field | Value |
|
||||
|
||||
Reference in New Issue
Block a user