mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
feat(dsh): remote managed-agent as on-demand tool + bl managed-agent run
Rework the managed-agent integration so a dsh user can, in plain language, have a Bailian cloud agent created and run a task — no hand-written agents.yaml, no prior apply. New `bl managed-agent run --prompt <task> [--instructions] [--model] [--agent]`: one step that idempotently materializes a cloud agent + its environment, then opens a session and streams the result. It mirrors the OpenAgentPack webui backend's ensure+run recipe (resolveProjectConfigFrom Object → syncAgentResourcesWithStateBackend → readProjectRuntime + startSessionRun) from an in-memory config, reusing the existing credential spine in _engine/credentials.ts. State persists under the bl config dir (~/.bailian/managed-agent/<agent>/), never the user's cwd, so repeat runs with the same --agent reuse the materialized agent. Unlike apply it provisions without --yes, since running is the intent. dsh side: replace the SubagentProvider with a plain tool `bailian_run_remote_task` (packages/dsh/src/tool-managed-agent). The subagent seam did not fit: in the web profile every tool-subagent row is disabled in the host plane (delegation lives in agent presets), a provider fixes one agent identity in config, and the default numeric maxDepth would fail-mount a no-depthLimit provider. As a tool the model calls it directly and fills `instructions` from the user's intent, so the remote agent's role is defined per task. Enabled by default — it creates nothing at load, only on invocation. LLM row: configure the base bundle's existing llm-pi-ai row instead of mounting a second pi-ai instance (a second instance re-declares pi-ai's global configurable-provider catalog and fails boot on a duplicate amazon-bedrock). TokenPlan reads a dedicated BAILIAN_TOKENPLAN_API_KEY, not DASHSCOPE_API_KEY: TokenPlan (sk-sp-) and pay-as-you-go (sk-ws-) keys 401 each other's endpoints, so sharing one var would silently break whichever plugin lost. Note: the ensure+run happy path could not be verified end-to-end on the available account — agentstudio returns 404 there, and the existing `managed-agent apply` 404s identically against the same endpoint/key, so the failure is account/service provisioning, not this change. Command wiring, dry-run, config assembly, credential injection and URL construction were all verified. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,7 @@ import {
|
||||
managedAgentValidate,
|
||||
managedAgentPlan,
|
||||
managedAgentApply,
|
||||
managedAgentRun,
|
||||
managedAgentDestroy,
|
||||
managedAgentStateList,
|
||||
managedAgentStateShow,
|
||||
@@ -225,6 +226,7 @@ export const commands: Record<string, AnyCommand> = {
|
||||
"managed-agent validate": managedAgentValidate,
|
||||
"managed-agent plan": managedAgentPlan,
|
||||
"managed-agent apply": managedAgentApply,
|
||||
"managed-agent run": managedAgentRun,
|
||||
"managed-agent destroy": managedAgentDestroy,
|
||||
"managed-agent state list": managedAgentStateList,
|
||||
"managed-agent state show": managedAgentStateShow,
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import {
|
||||
type BackendRuntimeInput,
|
||||
LocalFileStateBackend,
|
||||
resolveProjectConfigFromObject,
|
||||
} from "@openagentpack/sdk";
|
||||
import { getConfigDir } from "bailian-cli-core";
|
||||
import {
|
||||
assertProviderCredentials,
|
||||
type CredentialHost,
|
||||
injectProviderCredentials,
|
||||
normalizeInterpolatedProviderBlocks,
|
||||
prepareProviderEnv,
|
||||
scrubCredentialEnv,
|
||||
} from "./credentials.ts";
|
||||
import { type HostContext, installSdkTransport } from "./transport.ts";
|
||||
|
||||
/** Default agent identity `bl managed-agent run` materializes and reuses. */
|
||||
export const DEFAULT_INLINE_AGENT = "dsh-remote-runner";
|
||||
|
||||
/** Default model for the materialized agent. */
|
||||
export const DEFAULT_INLINE_MODEL = "qwen3.8-max";
|
||||
|
||||
/** Default role when the caller supplies no `--instructions`. */
|
||||
export const DEFAULT_INLINE_INSTRUCTIONS = "You are a helpful assistant. Complete the task.";
|
||||
|
||||
/** Environment name declared in the inline config; one cloud env per agent. */
|
||||
const INLINE_ENVIRONMENT = "cloud";
|
||||
|
||||
export interface InlineAgentOptions {
|
||||
agentName: string;
|
||||
instructions: string;
|
||||
model: string;
|
||||
/** Override the persisted state location (defaults under the bl config dir). */
|
||||
statePath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slugify an agent name into a filesystem- and project-id-safe token. The state
|
||||
* for each distinct agent lives in its own directory so repeat runs reuse the
|
||||
* same materialized remote agent.
|
||||
*/
|
||||
function slugify(agentName: string): string {
|
||||
const slug = agentName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9._-]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
return slug.length > 0 ? slug : "agent";
|
||||
}
|
||||
|
||||
/** Where a materialized agent's state is persisted (not the user's cwd). */
|
||||
export function inlineStatePath(agentName: string): string {
|
||||
return join(getConfigDir(), "managed-agent", slugify(agentName), "state.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimal in-memory project config that materializes into one cloud agent.
|
||||
* `providers.bailian` carries empty `api_key`/`base_url` placeholders so
|
||||
* {@link injectProviderCredentials} fills them from bl's auth chain (it only
|
||||
* writes fields the block already declares).
|
||||
*/
|
||||
export function buildInlineConfig(opts: InlineAgentOptions): Record<string, unknown> {
|
||||
return {
|
||||
version: "1",
|
||||
providers: {
|
||||
bailian: { api_key: "", base_url: "" },
|
||||
},
|
||||
defaults: { provider: "bailian" },
|
||||
environments: {
|
||||
[INLINE_ENVIRONMENT]: {
|
||||
description: "Bailian CLI cloud environment",
|
||||
config: { type: "cloud", networking: { type: "unrestricted" } },
|
||||
},
|
||||
},
|
||||
agents: {
|
||||
[opts.agentName]: {
|
||||
description: opts.agentName,
|
||||
model: opts.model,
|
||||
instructions: opts.instructions,
|
||||
environment: INLINE_ENVIRONMENT,
|
||||
provider: "bailian",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the `BackendRuntimeInput` shared by ensure (`syncAgentResourcesWith
|
||||
* StateBackend`) and run (`readProjectRuntime` + `startSessionRun`). Mirrors the
|
||||
* credential spine of {@link buildAgentRuntime} but sources config from an
|
||||
* in-memory object instead of a file, so no `agents.yaml` or `apply` is required.
|
||||
*/
|
||||
export async function buildInlineBackendInput(
|
||||
host: HostContext & CredentialHost,
|
||||
opts: InlineAgentOptions,
|
||||
): Promise<BackendRuntimeInput> {
|
||||
installSdkTransport(host);
|
||||
prepareProviderEnv();
|
||||
|
||||
const rawConfig = buildInlineConfig(opts);
|
||||
const { config, projectName } = await resolveProjectConfigFromObject(rawConfig, {
|
||||
projectName: slugify(opts.agentName),
|
||||
});
|
||||
|
||||
normalizeInterpolatedProviderBlocks(config.providers);
|
||||
injectProviderCredentials(config.providers, host);
|
||||
scrubCredentialEnv();
|
||||
assertProviderCredentials(config.providers);
|
||||
|
||||
const statePath = opts.statePath ?? inlineStatePath(opts.agentName);
|
||||
mkdirSync(dirname(statePath), { recursive: true });
|
||||
const stateBackend = new LocalFileStateBackend({ statePath });
|
||||
|
||||
return {
|
||||
projectName,
|
||||
config,
|
||||
stateBackend,
|
||||
stateScope: { projectId: slugify(opts.agentName) },
|
||||
providers: config.providers,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import {
|
||||
BailianError,
|
||||
defineCommand,
|
||||
detectOutputFormat,
|
||||
ExitCode,
|
||||
type FlagsDef,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult } from "bailian-cli-runtime";
|
||||
import {
|
||||
readProjectRuntime,
|
||||
startSessionRun,
|
||||
startSessionRunPolling,
|
||||
syncAgentResourcesWithStateBackend,
|
||||
} from "@openagentpack/sdk";
|
||||
import { CREDENTIALS_NOTE } from "./_engine/config-loader.ts";
|
||||
import { withStdoutProtected } from "./_engine/console-capture.ts";
|
||||
import { withAgentErrors } from "./_engine/errors.ts";
|
||||
import {
|
||||
buildInlineBackendInput,
|
||||
DEFAULT_INLINE_AGENT,
|
||||
DEFAULT_INLINE_INSTRUCTIONS,
|
||||
DEFAULT_INLINE_MODEL,
|
||||
} from "./_engine/inline-runtime.ts";
|
||||
import { renderCollectedEvents, streamAndRenderEvents } from "./_engine/session-render.ts";
|
||||
|
||||
const RUN_FLAGS = {
|
||||
prompt: {
|
||||
type: "string",
|
||||
valueHint: "<text>",
|
||||
description: "Task to run (required)",
|
||||
required: true,
|
||||
},
|
||||
instructions: {
|
||||
type: "string",
|
||||
valueHint: "<text>",
|
||||
description: "Role/system instructions for the remote agent (default: generic assistant)",
|
||||
},
|
||||
model: {
|
||||
type: "string",
|
||||
valueHint: "<id>",
|
||||
description: `Model for the remote agent (default: ${DEFAULT_INLINE_MODEL})`,
|
||||
},
|
||||
agent: {
|
||||
type: "string",
|
||||
valueHint: "<name>",
|
||||
description: `Agent identity to create/reuse (default: ${DEFAULT_INLINE_AGENT})`,
|
||||
},
|
||||
noStream: {
|
||||
type: "switch",
|
||||
description: "Use polling instead of SSE streaming",
|
||||
},
|
||||
} satisfies FlagsDef;
|
||||
|
||||
export default defineCommand({
|
||||
description: "Provision (if needed) a cloud agent and run a task in one step",
|
||||
auth: "apiKey",
|
||||
usageArgs: "--prompt <text> [--instructions <text>] [--model <id>] [--agent <name>]",
|
||||
flags: RUN_FLAGS,
|
||||
exampleArgs: [
|
||||
'--prompt "Summarize the latest AI news"',
|
||||
'--prompt "Audit this dependency tree" --instructions "You are a security expert" --model qwen3.8-max',
|
||||
],
|
||||
notes: [
|
||||
...CREDENTIALS_NOTE,
|
||||
"Unlike `apply`, this creates/updates the cloud agent + environment on demand without --yes. The first run provisions cloud resources (may incur cost and take longer to start); later runs with the same --agent reuse them.",
|
||||
],
|
||||
async run(ctx) {
|
||||
const { settings, flags } = ctx;
|
||||
const format = detectOutputFormat(settings.output);
|
||||
const asJson = format === "json";
|
||||
|
||||
const agentName = flags.agent ?? DEFAULT_INLINE_AGENT;
|
||||
const model = flags.model ?? DEFAULT_INLINE_MODEL;
|
||||
const instructions = flags.instructions ?? DEFAULT_INLINE_INSTRUCTIONS;
|
||||
|
||||
if (settings.dryRun) {
|
||||
emitResult(
|
||||
{
|
||||
would_run: {
|
||||
prompt: flags.prompt,
|
||||
agent: agentName,
|
||||
model,
|
||||
instructions,
|
||||
mode: flags.noStream ? "polling" : "streaming",
|
||||
},
|
||||
},
|
||||
format,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await withAgentErrors(() =>
|
||||
withStdoutProtected(async () => {
|
||||
const input = await buildInlineBackendInput(ctx, { agentName, instructions, model });
|
||||
|
||||
// Ensure the remote agent + its cloud environment exist. Idempotent:
|
||||
// a repeat run with the same agent name reuses the materialized state.
|
||||
if (!asJson) process.stderr.write(`Ensuring cloud agent "${agentName}"…\n`);
|
||||
const sync = await syncAgentResourcesWithStateBackend(input, agentName, {
|
||||
policy: "force",
|
||||
quiet: true,
|
||||
});
|
||||
if (sync.status !== "completed") {
|
||||
const detail =
|
||||
sync.error ??
|
||||
sync.diagnostics.find((diag) => diag.severity === "error")?.message ??
|
||||
`provisioning ended with status "${sync.status}"`;
|
||||
throw new BailianError(
|
||||
`Failed to provision cloud agent "${agentName}": ${detail}`,
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
// Run the task inside a runtime bound to the just-materialized state.
|
||||
await readProjectRuntime(input, async (runtime) => {
|
||||
if (flags.noStream) {
|
||||
const run = await startSessionRunPolling(runtime, flags.prompt, { agent: agentName });
|
||||
if (!asJson) process.stderr.write(`Session created: ${run.session.id}\n`);
|
||||
renderCollectedEvents(run, asJson, {
|
||||
session_id: run.session.id,
|
||||
provider: run.provider,
|
||||
agent: run.agentName,
|
||||
});
|
||||
} else {
|
||||
const run = await startSessionRun(runtime, flags.prompt, { agent: agentName });
|
||||
if (!asJson) process.stderr.write(`Session created: ${run.session.id}\n`);
|
||||
await streamAndRenderEvents(run.events, asJson, {
|
||||
session_id: run.session.id,
|
||||
provider: run.provider,
|
||||
agent: run.agentName,
|
||||
});
|
||||
}
|
||||
});
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -99,6 +99,7 @@ export { default as managedAgentInit } from "./commands/managed-agent/init.ts";
|
||||
export { default as managedAgentValidate } from "./commands/managed-agent/validate.ts";
|
||||
export { default as managedAgentPlan } from "./commands/managed-agent/plan.ts";
|
||||
export { default as managedAgentApply } from "./commands/managed-agent/apply.ts";
|
||||
export { default as managedAgentRun } from "./commands/managed-agent/run.ts";
|
||||
export { default as managedAgentDestroy } from "./commands/managed-agent/destroy.ts";
|
||||
export { default as managedAgentStateList } from "./commands/managed-agent/state-list.ts";
|
||||
export { default as managedAgentStateShow } from "./commands/managed-agent/state-show.ts";
|
||||
|
||||
@@ -177,6 +177,7 @@ export const MANAGED_AGENT_ROUTES: E2eRouteExports = {
|
||||
"managed-agent validate": "managedAgentValidate",
|
||||
"managed-agent plan": "managedAgentPlan",
|
||||
"managed-agent apply": "managedAgentApply",
|
||||
"managed-agent run": "managedAgentRun",
|
||||
"managed-agent destroy": "managedAgentDestroy",
|
||||
"managed-agent state list": "managedAgentStateList",
|
||||
"managed-agent state rm": "managedAgentStateRm",
|
||||
|
||||
+33
-36
@@ -4,23 +4,23 @@
|
||||
|
||||
一个包提供 5 个插件行,外加对 base bundle 的 `llm-pi-ai` 行做一次配置覆盖:
|
||||
|
||||
| row id | 能力 | 默认 | 依赖 |
|
||||
| -------------------------------- | --------------------------------------------------------------- | ---- | --------------------- |
|
||||
| `llm-pi-ai`(覆盖 base 行) | 把百炼 TokenPlan 网关注册成 LLM provider(`bailian-tokenplan`) | 启用 | TokenPlan Key |
|
||||
| `bailian-tool-vision` | `bailian_vision_describe`:图片/视频理解 | 启用 | `bl` |
|
||||
| `bailian-tool-image` | `bailian_image_generate`:文生图 | 启用 | `bl` |
|
||||
| `bailian-web-search-rag` | 百炼知识库检索,注册为 `web_search` 的后端 | 停用 | 按量付费 Key + 知识库 |
|
||||
| `bailian-memory` | 跨会话长期记忆(tools + 自动检索/落库) | 停用 | 按量付费 Key |
|
||||
| `bailian-subagent-managed-agent` | 子 agent 跑在百炼托管运行时 | 停用 | `bl` + `agents.yaml` |
|
||||
| row id | 能力 | 默认 | 依赖 |
|
||||
| ---------------------------- | --------------------------------------------------------------- | ---- | --------------------- |
|
||||
| `llm-pi-ai`(覆盖 base 行) | 把百炼 TokenPlan 网关注册成 LLM provider(`bailian-tokenplan`) | 启用 | TokenPlan Key |
|
||||
| `bailian-tool-vision` | `bailian_vision_describe`:图片/视频理解 | 启用 | `bl` |
|
||||
| `bailian-tool-image` | `bailian_image_generate`:文生图 | 启用 | `bl` |
|
||||
| `bailian-tool-managed-agent` | `bailian_run_remote_task`:按需在云端创建 agent 并跑任务 | 启用 | `bl` + 按量付费 Key |
|
||||
| `bailian-web-search-rag` | 百炼知识库检索,注册为 `web_search` 的后端 | 停用 | 按量付费 Key + 知识库 |
|
||||
| `bailian-memory` | 跨会话长期记忆(tools + 自动检索/落库) | 停用 | 按量付费 Key |
|
||||
|
||||
后三个默认停用是有意的:它们要么需要部署方特有的资源 ID,要么按次计费,不该在用户没配置时就生效。
|
||||
`web-search-rag` 与 `memory` 默认停用是有意的:它们要么需要部署方特有的资源 ID,要么按次计费,不该在用户没配置时就生效。`tool-managed-agent` 默认启用——它加载时不建任何资源,只有模型真正调用时才在云端创建 agent。
|
||||
|
||||
---
|
||||
|
||||
## 1. 前置条件
|
||||
|
||||
- Node ≥ 22.19(`dsh` 的要求)
|
||||
- `bl`(vision / image / subagent 三个插件通过子进程调它)
|
||||
- `bl`(vision / image / 远程任务 三个工具通过子进程调它)
|
||||
|
||||
```sh
|
||||
npm install -g bailian-cli
|
||||
@@ -105,7 +105,9 @@ Web UI 在 http://127.0.0.1:3080。
|
||||
| `deepseek-v4-pro` | 否 |
|
||||
| `deepseek-v4-flash-0731` | 否 |
|
||||
|
||||
**两个工具** — `bailian_vision_describe`、`bailian_image_generate`。
|
||||
**三个工具** — `bailian_vision_describe`、`bailian_image_generate`、`bailian_run_remote_task`。
|
||||
|
||||
前两个走 TokenPlan(vision/image)。`bailian_run_remote_task` 见 [§3.1](#31-远程任务-bailian_run_remote_task)——它默认启用但用的是**按量付费 Key + dashscope 端点**,与 TokenPlan 那两个不同。
|
||||
|
||||
### 关于看图,有个坑值得知道
|
||||
|
||||
@@ -118,6 +120,24 @@ DeepSeek 那两个模型在 TokenPlan 网关上传图**不报错但也看不见*
|
||||
|
||||
`bailian_image_generate` 同理:模型能看图时返回内联图片,不能看图时降级为返回落盘路径,你可以接着用 vision 工具读它。文件不会被删除,正是为了这个衔接。
|
||||
|
||||
### 3.1 远程任务(`bailian_run_remote_task`)
|
||||
|
||||
把一个任务甩到百炼云端的托管 agent 上跑,不占本地会话。**无需预先写 `agents.yaml` 或 `apply`**:工具首次被调用时,`bl managed-agent run` 会在你的账号里幂等创建一个 agent + cloud environment,之后复用。
|
||||
|
||||
- 模型自己按用户意图填 `instructions`(远程 agent 的角色),`task` 是要它做的事。例如你说「在云端帮我审计这个依赖树,它该懂安全」→ 模型调 `bailian_run_remote_task(task="审计依赖树", instructions="你是安全专家")`。
|
||||
- **前提**:这条路走的是 managed-agent(agentstudio)服务,需要**按量付费 Key**(`sk-ws-`)+ dashscope 端点,且账号已开通 managed-agent。TokenPlan Key 不适用。若 `DASHSCOPE_API_KEY`/端点没配好,首次调用会返回 `Bailian API 404`。
|
||||
- 首次会创建云资源(可能计费、启动有延迟);同名 agent 后续复用。默认 agent 名 `dsh-remote-runner`,可在配置里改。
|
||||
|
||||
需要非默认的 agent 名 / 模型时:
|
||||
|
||||
```yaml
|
||||
- id: bailian-tool-managed-agent
|
||||
config:
|
||||
agent: my-runner
|
||||
model: qwen3.8-max
|
||||
timeoutMs: 600000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 开启可选插件
|
||||
@@ -181,30 +201,7 @@ dsh 自身没有跨会话记忆(`ctx.compaction` 只在单会话内压缩上
|
||||
autoPersist: false
|
||||
```
|
||||
|
||||
### 托管子 agent
|
||||
|
||||
把 dsh 的子 agent 派发到百炼云端运行,不占本地资源。
|
||||
|
||||
先在工作目录准备好清单并应用:
|
||||
|
||||
```sh
|
||||
bl managed-agent init
|
||||
bl managed-agent apply --yes
|
||||
```
|
||||
|
||||
再开启:
|
||||
|
||||
```yaml
|
||||
- id: bailian-subagent-managed-agent
|
||||
disabled: false
|
||||
config:
|
||||
file: agents.yaml
|
||||
agent: assistant
|
||||
provider: bailian
|
||||
timeoutMs: 600000
|
||||
```
|
||||
|
||||
两个已知限制:CLI 在会话结束时才一次性输出 JSON,所以**中途没有增量进度**,被取消时也拿不到部分输出;`prepareContinuable` 未实现,即只支持一次性委派,不支持多轮续聊。
|
||||
> 远程任务(`bailian_run_remote_task`)默认启用,配置见 [§3.1](#31-远程任务-bailian_run_remote_task)。
|
||||
|
||||
---
|
||||
|
||||
@@ -226,7 +223,7 @@ bl auth status
|
||||
- **文生图**:让模型生成一张图
|
||||
- **RAG**:问一个只有知识库里才有答案的问题
|
||||
- **记忆**:会话 A 告诉它一个事实 → 关掉 → 新开会话 B 提问,看是否命中
|
||||
- **子 agent**:派发一个子任务
|
||||
- **远程任务**:说「在云端帮我跑一个任务:<something>,它该擅长 <role>」→ 确认模型调用 `bailian_run_remote_task`(`instructions` 由模型按 role 填)→ 首次触发云端创建 → 返回远程会话结果(需按量付费 Key + 已开通 agentstudio)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -76,6 +76,12 @@
|
||||
- id: bailian-tool-image
|
||||
name: bailian-cli-dsh/tool-image
|
||||
|
||||
# Enabled by default: the tool creates no resources at load time. It only
|
||||
# provisions a cloud agent when the model actually calls it, and reuses it
|
||||
# after — no deployment-specific ID to configure up front.
|
||||
- id: bailian-tool-managed-agent
|
||||
name: bailian-cli-dsh/tool-managed-agent
|
||||
|
||||
# Disabled by default: the knowledge base to query is deployment-specific,
|
||||
# and an enabled provider with no agentId would make `web_search` ambiguous
|
||||
# for everyone. Set workspaceId + agentId and flip `disabled` to use it.
|
||||
@@ -89,9 +95,3 @@
|
||||
name: bailian-cli-dsh/memory
|
||||
disabled: true
|
||||
config: {}
|
||||
|
||||
# Disabled by default: requires an applied `agents.yaml` in the workspace.
|
||||
- id: bailian-subagent-managed-agent
|
||||
name: bailian-cli-dsh/subagent-managed-agent
|
||||
disabled: true
|
||||
config: {}
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
"types": "./src/tool-image/index.ts",
|
||||
"default": "./src/tool-image/index.ts"
|
||||
},
|
||||
"./tool-managed-agent": {
|
||||
"types": "./src/tool-managed-agent/index.ts",
|
||||
"default": "./src/tool-managed-agent/index.ts"
|
||||
},
|
||||
"./web-search-rag": {
|
||||
"types": "./src/web-search-rag/index.ts",
|
||||
"default": "./src/web-search-rag/index.ts"
|
||||
@@ -41,10 +45,6 @@
|
||||
"types": "./src/memory/index.ts",
|
||||
"default": "./src/memory/index.ts"
|
||||
},
|
||||
"./subagent-managed-agent": {
|
||||
"types": "./src/subagent-managed-agent/index.ts",
|
||||
"default": "./src/subagent-managed-agent/index.ts"
|
||||
},
|
||||
"./cordis.patch.yml": "./cordis.patch.yml",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
@@ -54,9 +54,9 @@
|
||||
".": "./dist/index.mjs",
|
||||
"./tool-vision": "./dist/tool-vision/index.mjs",
|
||||
"./tool-image": "./dist/tool-image/index.mjs",
|
||||
"./tool-managed-agent": "./dist/tool-managed-agent/index.mjs",
|
||||
"./web-search-rag": "./dist/web-search-rag/index.mjs",
|
||||
"./memory": "./dist/memory/index.mjs",
|
||||
"./subagent-managed-agent": "./dist/subagent-managed-agent/index.mjs",
|
||||
"./cordis.patch.yml": "./cordis.patch.yml",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/**
|
||||
* `bailian-cli-dsh/subagent-managed-agent`: runs child agents on Bailian's
|
||||
* hosted managed-agent runtime instead of in this process, through
|
||||
* `bl managed-agent session run`.
|
||||
*
|
||||
* Out-of-process delegation is an established shape here — `subagent-acp` and
|
||||
* `subagent-codex` do the same over their own transports. Going through the
|
||||
* CLI keeps `agents.yaml` resolution, provider selection, and SSE decoding in
|
||||
* one place.
|
||||
*
|
||||
* Two honest limits. The CLI buffers the whole session and emits it at exit,
|
||||
* so no incremental progress reaches the parent and a cancelled run yields no
|
||||
* partial output. And `prepareContinuable` is deliberately absent: method
|
||||
* presence IS the continuable capability, and multi-turn continuation is not
|
||||
* wired up yet.
|
||||
*
|
||||
* @module bailian-cli-dsh/subagent-managed-agent
|
||||
*/
|
||||
import type { Context } from "@deepseek-ai/cordis";
|
||||
import type { ContentBlock } from "@deepseek-ai/dsh-llm";
|
||||
import { SessionId } from "@deepseek-ai/dsh-session";
|
||||
import type {
|
||||
ResolvedSubagentStartRequest,
|
||||
SubagentCapabilities,
|
||||
SubagentProvider,
|
||||
SubagentResult,
|
||||
SubagentRun,
|
||||
} from "@deepseek-ai/dsh-subagent";
|
||||
import type {} from "@deepseek-ai/dsh-fs";
|
||||
import z from "@deepseek-ai/schemastery";
|
||||
import { runBlJson } from "../shared/bl.ts";
|
||||
|
||||
/** Cordis plugin name used by loader diagnostics. */
|
||||
export const name = "bailian-subagent-managed-agent";
|
||||
|
||||
/** Seams this plugin registers into. */
|
||||
export const inject = ["subagents", "subprocess", "fs"];
|
||||
|
||||
/** Registry name callers select this transport by. */
|
||||
export const BAILIAN_MANAGED_AGENT_PROVIDER = "bailian-managed-agent";
|
||||
|
||||
export interface Config {
|
||||
/** Manifest passed as `--file`; must already be applied. */
|
||||
file?: string;
|
||||
/** Agent name within the manifest. */
|
||||
agent?: string;
|
||||
/** Backing provider understood by `bl managed-agent`. */
|
||||
provider?: string;
|
||||
/** Cooperative budget for one hosted run. */
|
||||
timeoutMs?: number;
|
||||
}
|
||||
|
||||
export const Config: z<Config> = z.object({
|
||||
file: z.string().description("Path to agents.yaml; defaults to the CLI's own default."),
|
||||
agent: z.string().description("Agent name declared in the manifest."),
|
||||
provider: z.string().description("Managed-agent backing provider."),
|
||||
timeoutMs: z.natural().description("Cooperative timeout budget in milliseconds."),
|
||||
});
|
||||
|
||||
const DEFAULT_MANIFEST = "agents.yaml";
|
||||
const DEFAULT_TIMEOUT_MS = 600_000;
|
||||
|
||||
/** A one-shot transport supports none of the start-time features. */
|
||||
const CAPABILITIES: SubagentCapabilities = {
|
||||
outputSchema: false,
|
||||
depthLimit: false,
|
||||
toolFilter: false,
|
||||
persona: false,
|
||||
};
|
||||
|
||||
interface SessionEvent {
|
||||
type?: string;
|
||||
content?: unknown;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
interface SessionRunResponse {
|
||||
session_id?: string;
|
||||
events?: readonly SessionEvent[];
|
||||
}
|
||||
|
||||
function promptText(blocks: readonly ContentBlock[]): string {
|
||||
return blocks
|
||||
.filter((block): block is Extract<ContentBlock, { type: "text" }> => block.type === "text")
|
||||
.map((block) => block.text)
|
||||
.join("\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/** Assistant-visible text of a finished hosted session. */
|
||||
function assistantOutput(events: readonly SessionEvent[]): ContentBlock[] {
|
||||
const text = events
|
||||
.filter((event) => event.type === "message" && typeof event.content === "string")
|
||||
.map((event) => event.content as string)
|
||||
.join("\n")
|
||||
.trim();
|
||||
return text.length > 0 ? [{ type: "text", text }] : [];
|
||||
}
|
||||
|
||||
function isAbort(error: unknown): boolean {
|
||||
return error instanceof DOMException && error.name === "AbortError";
|
||||
}
|
||||
|
||||
class BailianManagedAgentProvider implements SubagentProvider {
|
||||
readonly name = BAILIAN_MANAGED_AGENT_PROVIDER;
|
||||
readonly capabilities = CAPABILITIES;
|
||||
readonly inheritsParentContext = false;
|
||||
|
||||
constructor(
|
||||
private readonly ctx: Context,
|
||||
private readonly config: Config,
|
||||
) {}
|
||||
|
||||
async start(request: ResolvedSubagentStartRequest): Promise<SubagentRun> {
|
||||
const cwd = request.parent.session.header.cwd ?? process.cwd();
|
||||
const manifest = this.config.file ?? DEFAULT_MANIFEST;
|
||||
|
||||
// Pre-publication: a missing manifest is the common misconfiguration and
|
||||
// deserves a start-time rejection rather than a failed run.
|
||||
const target = await this.ctx.fs.resolve(manifest, { cwd, signal: request.signal });
|
||||
const info = await this.ctx.fs.stat(target, request.signal);
|
||||
if (info === undefined) {
|
||||
throw new Error(
|
||||
`bailian-managed-agent: no manifest at "${target.displayPath}". Create one with ` +
|
||||
`\`bl managed-agent init\` and apply it with \`bl managed-agent apply --yes\`.`,
|
||||
);
|
||||
}
|
||||
|
||||
const prompt = promptText(request.prompt);
|
||||
if (prompt.length === 0) {
|
||||
throw new Error("bailian-managed-agent: the prompt carried no text content.");
|
||||
}
|
||||
|
||||
const argv = ["managed-agent", "session", "run", "--prompt", prompt, "--file", manifest];
|
||||
if (this.config.agent !== undefined) argv.push("--agent", this.config.agent);
|
||||
if (this.config.provider !== undefined) argv.push("--provider", this.config.provider);
|
||||
|
||||
const controller = new AbortController();
|
||||
const abort = (): void => controller.abort();
|
||||
request.signal.addEventListener("abort", abort, { once: true });
|
||||
|
||||
// The seam has no deadline of its own — cancellation arrives only through
|
||||
// the caller's signal — so the transport owns one, or a wedged hosted
|
||||
// session never settles.
|
||||
const deadline = AbortSignal.timeout(this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
||||
const combined = AbortSignal.any([controller.signal, deadline]);
|
||||
|
||||
// Ownership transfers on fulfillment, so every later failure settles
|
||||
// through `result` — which must not reject for child-level problems.
|
||||
const result = this.execute(argv, cwd, combined, deadline).finally(() => {
|
||||
request.signal.removeEventListener("abort", abort);
|
||||
});
|
||||
|
||||
let disposal: Promise<void> | undefined;
|
||||
return {
|
||||
id: SessionId(`bailian-managed-agent:${crypto.randomUUID()}`),
|
||||
localAgent: undefined,
|
||||
result,
|
||||
dispose: (): Promise<void> => {
|
||||
disposal ??= (async (): Promise<void> => {
|
||||
controller.abort();
|
||||
await result;
|
||||
})();
|
||||
return disposal;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private async execute(
|
||||
argv: readonly string[],
|
||||
cwd: string,
|
||||
signal: AbortSignal,
|
||||
deadline: AbortSignal,
|
||||
): Promise<SubagentResult> {
|
||||
try {
|
||||
const response = await runBlJson<SessionRunResponse>(this.ctx, argv, {
|
||||
cwd,
|
||||
signal,
|
||||
graceMs: 10_000,
|
||||
});
|
||||
return { output: assistantOutput(response.events ?? []), stopReason: "completed" };
|
||||
} catch (error) {
|
||||
if (deadline.aborted) {
|
||||
return {
|
||||
output: [
|
||||
{
|
||||
type: "text",
|
||||
text: `the hosted session exceeded ${this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS}ms and was terminated`,
|
||||
},
|
||||
],
|
||||
stopReason: "error",
|
||||
};
|
||||
}
|
||||
// The CLI emits its JSON envelope only at exit, so a cancelled run has
|
||||
// no partial output to salvage.
|
||||
if (isAbort(error) || signal.aborted) return { output: [], stopReason: "aborted" };
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
return { output: [{ type: "text", text: reason }], stopReason: "error" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function apply(ctx: Context, config: Config): void {
|
||||
ctx.subagents.registerProvider(new BailianManagedAgentProvider(ctx, config));
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* `bailian-cli-dsh/tool-managed-agent`: run a task on a Bailian-hosted managed
|
||||
* agent, provisioned on demand, through `bl managed-agent run`.
|
||||
*
|
||||
* A plain tool rather than a `SubagentProvider`: in dsh's `web` profile every
|
||||
* `tool-subagent` row is disabled in the host plane (delegation tools live in
|
||||
* agent presets), and a subagent provider fixes one agent identity in config —
|
||||
* neither fits "the model describes an intent and a remote agent is created for
|
||||
* it". As a tool the model calls it directly and fills `instructions` from the
|
||||
* user's intent, so the remote agent's role is defined per task.
|
||||
*
|
||||
* The CLI does ensure+run in one step: it materializes (idempotently) a cloud
|
||||
* agent + environment under the given `agent` name on first use and reuses them
|
||||
* after, so no `agents.yaml` or prior `apply` is required. First use provisions
|
||||
* cloud resources — it may incur cost and take longer to start.
|
||||
*
|
||||
* @module bailian-cli-dsh/tool-managed-agent
|
||||
*/
|
||||
import type { Context } from "@deepseek-ai/cordis";
|
||||
import { defineTool } from "@deepseek-ai/dsh-tools";
|
||||
import type {} from "@deepseek-ai/dsh-tools";
|
||||
import z from "@deepseek-ai/schemastery";
|
||||
import { runBlJson } from "../shared/bl.ts";
|
||||
|
||||
/** Cordis plugin name used by loader diagnostics. */
|
||||
export const name = "bailian-tool-managed-agent";
|
||||
|
||||
/** Seams this plugin registers into. */
|
||||
export const inject = ["tools", "subprocess"];
|
||||
|
||||
/** Default agent identity provisioned and reused across calls. */
|
||||
const DEFAULT_AGENT = "dsh-remote-runner";
|
||||
|
||||
export interface Config {
|
||||
/** Agent identity to create/reuse; distinct names get distinct remote agents. */
|
||||
agent?: string;
|
||||
/** Model for the remote agent. */
|
||||
model?: string;
|
||||
/** Cooperative budget; first-run provisioning of a cloud environment is slow. */
|
||||
timeoutMs?: number;
|
||||
}
|
||||
|
||||
export const Config: z<Config> = z.object({
|
||||
agent: z.string().description("Remote agent identity to create/reuse."),
|
||||
model: z.string().description("Model for the remote agent."),
|
||||
timeoutMs: z.natural().description("Cooperative timeout budget in milliseconds."),
|
||||
});
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 600_000;
|
||||
|
||||
/** The `bl managed-agent run --output json` envelope: a session-event list. */
|
||||
interface SessionRunResponse {
|
||||
session_id?: string;
|
||||
agent?: string;
|
||||
events?: readonly { type?: string; content?: unknown; role?: string }[];
|
||||
}
|
||||
|
||||
/** Assistant-visible text of a finished remote session. */
|
||||
function assistantText(response: SessionRunResponse): string {
|
||||
return (response.events ?? [])
|
||||
.filter((event) => event.type === "message" && typeof event.content === "string")
|
||||
.map((event) => event.content as string)
|
||||
.join("\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function apply(ctx: Context, config: Config): void {
|
||||
ctx.tools.register(
|
||||
defineTool({
|
||||
name: "bailian_run_remote_task",
|
||||
description:
|
||||
"Run a task on a Bailian-hosted cloud agent. Use for long-running or isolated work you " +
|
||||
"want executed remotely rather than in this session. A remote agent is created on demand " +
|
||||
"(and reused) — describe the role it should play through `instructions`, and the concrete " +
|
||||
"task through `task`. Returns the remote agent's final answer.",
|
||||
parameters: {
|
||||
task: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "The concrete task for the remote agent to carry out.",
|
||||
},
|
||||
instructions: {
|
||||
type: "string",
|
||||
description:
|
||||
"Role/system instructions defining what the remote agent is good at. " +
|
||||
"Defaults to a generic assistant.",
|
||||
},
|
||||
model: {
|
||||
type: "string",
|
||||
description: "Override the configured model for this task.",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
schema: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
answer: { type: "string", required: true },
|
||||
sessionId: { type: "string", required: true },
|
||||
},
|
||||
},
|
||||
render: (_args, value) => [{ type: "text", text: value.answer }],
|
||||
},
|
||||
timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
||||
async execute(args, exec) {
|
||||
const argv = [
|
||||
"managed-agent",
|
||||
"run",
|
||||
"--prompt",
|
||||
args.task,
|
||||
"--agent",
|
||||
config.agent ?? DEFAULT_AGENT,
|
||||
];
|
||||
if (args.instructions !== undefined) argv.push("--instructions", args.instructions);
|
||||
const model = args.model ?? config.model;
|
||||
if (model !== undefined) argv.push("--model", model);
|
||||
|
||||
const response = await runBlJson<SessionRunResponse>(ctx, argv, {
|
||||
cwd: exec.agent?.session.header.cwd ?? process.cwd(),
|
||||
signal: exec.signal,
|
||||
});
|
||||
|
||||
const answer = assistantText(response);
|
||||
if (answer.length === 0) {
|
||||
throw new Error("the remote agent produced no assistant output.");
|
||||
}
|
||||
return { answer, sessionId: response.session_id ?? "" };
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -8,9 +8,9 @@ export default defineConfig({
|
||||
"src/index.ts",
|
||||
"src/tool-vision/index.ts",
|
||||
"src/tool-image/index.ts",
|
||||
"src/tool-managed-agent/index.ts",
|
||||
"src/web-search-rag/index.ts",
|
||||
"src/memory/index.ts",
|
||||
"src/subagent-managed-agent/index.ts",
|
||||
],
|
||||
minify: true,
|
||||
dts: {
|
||||
|
||||
@@ -9,31 +9,32 @@ Use this index for the skill-scoped quick index and global flags.
|
||||
|
||||
## Quick index
|
||||
|
||||
| Command | Description | Detail |
|
||||
| --------------------------------- | ------------------------------------------------------------- | ------------------------------------ |
|
||||
| `bl managed-agent apply` | Apply planned changes to create/update/delete agent resources | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent destroy` | Destroy all managed agent resources tracked in state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent init` | Create a new agents.yaml template | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent plan` | Show what changes would be applied to agent infrastructure | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session create` | Create a new session for an agent | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session delete` | Delete a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session events` | List event history for a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session get` | Get details of a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session list` | List sessions from the provider | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session run` | Create a session, send a message, and stream the response | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session send` | Send a message to an existing session and stream the response | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent skill-list` | List skills from the provider's skill catalog | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state import` | Import an existing remote resource into agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state list` | List resources tracked in agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state rm` | Remove a resource from state without destroying it remotely | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state show` | Show details of a resource in agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent validate` | Validate an agents.yaml configuration (offline) | [managed-agent.md](managed-agent.md) |
|
||||
| Command | Description | Detail |
|
||||
| --------------------------------- | -------------------------------------------------------------- | ------------------------------------ |
|
||||
| `bl managed-agent apply` | Apply planned changes to create/update/delete agent resources | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent destroy` | Destroy all managed agent resources tracked in state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent init` | Create a new agents.yaml template | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent plan` | Show what changes would be applied to agent infrastructure | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent run` | Provision (if needed) a cloud agent and run a task in one step | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session create` | Create a new session for an agent | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session delete` | Delete a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session events` | List event history for a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session get` | Get details of a session | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session list` | List sessions from the provider | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session run` | Create a session, send a message, and stream the response | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent session send` | Send a message to an existing session and stream the response | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent skill-list` | List skills from the provider's skill catalog | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state import` | Import an existing remote resource into agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state list` | List resources tracked in agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state rm` | Remove a resource from state without destroying it remotely | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent state show` | Show details of a resource in agents state | [managed-agent.md](managed-agent.md) |
|
||||
| `bl managed-agent validate` | Validate an agents.yaml configuration (offline) | [managed-agent.md](managed-agent.md) |
|
||||
|
||||
## By group
|
||||
|
||||
| Group | Commands | Reference |
|
||||
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
||||
| `managed-agent` | `apply`, `destroy`, `init`, `plan`, `session create`, `session delete`, `session events`, `session get`, `session list`, `session run`, `session send`, `skill-list`, `state import`, `state list`, `state rm`, `state show`, `validate` | [managed-agent.md](managed-agent.md) |
|
||||
| Group | Commands | Reference |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
||||
| `managed-agent` | `apply`, `destroy`, `init`, `plan`, `run`, `session create`, `session delete`, `session events`, `session get`, `session list`, `session run`, `session send`, `skill-list`, `state import`, `state list`, `state rm`, `state show`, `validate` | [managed-agent.md](managed-agent.md) |
|
||||
|
||||
## Global flags
|
||||
|
||||
|
||||
@@ -7,25 +7,26 @@ Index: [index.md](index.md)
|
||||
|
||||
## Commands in this group
|
||||
|
||||
| Command | Description |
|
||||
| --------------------------------- | ------------------------------------------------------------- |
|
||||
| `bl managed-agent apply` | Apply planned changes to create/update/delete agent resources |
|
||||
| `bl managed-agent destroy` | Destroy all managed agent resources tracked in state |
|
||||
| `bl managed-agent init` | Create a new agents.yaml template |
|
||||
| `bl managed-agent plan` | Show what changes would be applied to agent infrastructure |
|
||||
| `bl managed-agent session create` | Create a new session for an agent |
|
||||
| `bl managed-agent session delete` | Delete a session |
|
||||
| `bl managed-agent session events` | List event history for a session |
|
||||
| `bl managed-agent session get` | Get details of a session |
|
||||
| `bl managed-agent session list` | List sessions from the provider |
|
||||
| `bl managed-agent session run` | Create a session, send a message, and stream the response |
|
||||
| `bl managed-agent session send` | Send a message to an existing session and stream the response |
|
||||
| `bl managed-agent skill-list` | List skills from the provider's skill catalog |
|
||||
| `bl managed-agent state import` | Import an existing remote resource into agents state |
|
||||
| `bl managed-agent state list` | List resources tracked in agents state |
|
||||
| `bl managed-agent state rm` | Remove a resource from state without destroying it remotely |
|
||||
| `bl managed-agent state show` | Show details of a resource in agents state |
|
||||
| `bl managed-agent validate` | Validate an agents.yaml configuration (offline) |
|
||||
| Command | Description |
|
||||
| --------------------------------- | -------------------------------------------------------------- |
|
||||
| `bl managed-agent apply` | Apply planned changes to create/update/delete agent resources |
|
||||
| `bl managed-agent destroy` | Destroy all managed agent resources tracked in state |
|
||||
| `bl managed-agent init` | Create a new agents.yaml template |
|
||||
| `bl managed-agent plan` | Show what changes would be applied to agent infrastructure |
|
||||
| `bl managed-agent run` | Provision (if needed) a cloud agent and run a task in one step |
|
||||
| `bl managed-agent session create` | Create a new session for an agent |
|
||||
| `bl managed-agent session delete` | Delete a session |
|
||||
| `bl managed-agent session events` | List event history for a session |
|
||||
| `bl managed-agent session get` | Get details of a session |
|
||||
| `bl managed-agent session list` | List sessions from the provider |
|
||||
| `bl managed-agent session run` | Create a session, send a message, and stream the response |
|
||||
| `bl managed-agent session send` | Send a message to an existing session and stream the response |
|
||||
| `bl managed-agent skill-list` | List skills from the provider's skill catalog |
|
||||
| `bl managed-agent state import` | Import an existing remote resource into agents state |
|
||||
| `bl managed-agent state list` | List resources tracked in agents state |
|
||||
| `bl managed-agent state rm` | Remove a resource from state without destroying it remotely |
|
||||
| `bl managed-agent state show` | Show details of a resource in agents state |
|
||||
| `bl managed-agent validate` | Validate an agents.yaml configuration (offline) |
|
||||
|
||||
## Command details
|
||||
|
||||
@@ -170,6 +171,43 @@ bl managed-agent plan --provider bailian
|
||||
bl managed-agent plan --no-refresh
|
||||
```
|
||||
|
||||
### `bl managed-agent run`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| **Name** | `managed-agent run` |
|
||||
| **Description** | Provision (if needed) a cloud agent and run a task in one step |
|
||||
| **Usage** | `bl managed-agent run --prompt <text> [--instructions <text>] [--model <id>] [--agent <name>]` |
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ----------------------- | ------ | -------- | -------------------------------------------------------------------------- |
|
||||
| `--prompt <text>` | string | yes | Task to run (required) |
|
||||
| `--instructions <text>` | string | no | Role/system instructions for the remote agent (default: generic assistant) |
|
||||
| `--model <id>` | string | no | Model for the remote agent (default: qwen3.8-max) |
|
||||
| `--agent <name>` | string | no | Agent identity to create/reuse (default: dsh-remote-runner) |
|
||||
| `--no-stream` | switch | no | Use polling instead of SSE streaming |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
|
||||
#### Notes
|
||||
|
||||
- Bailian credentials come from bl's auth chain: --api-key > DASHSCOPE_API_KEY > `bl auth login` (active config profile).
|
||||
- Other providers read the env vars referenced in agents.yaml (e.g. ${ANTHROPIC_API_KEY}), including .env and ~/.agents/config.json.
|
||||
- Resolved credentials are injected into the SDK in-memory and cleared from the environment; they never persist in process env.
|
||||
- Unlike `apply`, this creates/updates the cloud agent + environment on demand without --yes. The first run provisions cloud resources (may incur cost and take longer to start); later runs with the same --agent reuse them.
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl managed-agent run --prompt "Summarize the latest AI news"
|
||||
```
|
||||
|
||||
```bash
|
||||
bl managed-agent run --prompt "Audit this dependency tree" --instructions "You are a security expert" --model qwen3.8-max
|
||||
```
|
||||
|
||||
### `bl managed-agent session create`
|
||||
|
||||
| Field | Value |
|
||||
|
||||
Reference in New Issue
Block a user