mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 03:20:42 +00:00
feat: add subagent delegation preference mode
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Tests/Docker: add Codex on-demand install and live plugin-tool dependency E2E lanes for packaged onboarding and npm-pack plugin proof.
|
||||
- Plugins/ACPX: accept an optional `args` array in `agents.<name>` config so paths and flag values containing spaces stay intact when spawning ACP agent processes. Thanks @TheArchitectit and @BunsDev.
|
||||
- Agents: inject the current provider/model identity into system prompts, including configured prompt overrides and CLI hook prompt replacements, so agents can answer model-identity questions from the actual runtime selection.
|
||||
- Agents/subagents: add prompt-only `agents.defaults.subagents.delegationMode` and per-agent overrides with `suggest`/`prefer` modes, and centralize config-backed system prompt resolution across embedded, CLI, compaction, and command-export prompt surfaces.
|
||||
- Plugins/CLI: add the optional bundled `oc-path` plugin, providing `openclaw path` for surgical `oc://` access to markdown, JSONC, and JSONL workspace files.
|
||||
- Plugins/SDK: add unified model catalog registration for text, image, video, and music providers, including `providerCatalogEntry` manifests, shared media list help, live catalog caching, and per-model video capability overlays.
|
||||
- Plugin SDK: add presentation helpers for controls-only interactive rendering and opt-in empty fallback text so rich channel renderers can share `MessagePresentation` semantics without duplicating native cards or components.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
7d7ecfff72edaa6125c2b3e858c3f6dfbcc8942bb19abd8fee22797f618199f5 config-baseline.json
|
||||
eec702624d26e2c5d6fda7cbcb573beaad223dd549c7f2927d4220f893fbe7a0 config-baseline.core.json
|
||||
bb53a92a54a804d217baf466a4731924653d769db37122c38400cc3b97720c23 config-baseline.json
|
||||
3b632b0f038846722e2a5012a5eeec2a29048b6e385b591d7bd9122aa0981a20 config-baseline.core.json
|
||||
9edc62ae7dfedabc645470dd03102b813fc780b9108caf675fd661104714206f config-baseline.channel.json
|
||||
1da42cb10427fb08510f29732493d24851ab915a424f91556569febdd450d9c3 config-baseline.plugin.json
|
||||
|
||||
@@ -57,7 +57,7 @@ Tune queue and model capacity around the business value of each lane:
|
||||
agents: {
|
||||
defaults: {
|
||||
maxConcurrent: 4,
|
||||
subagents: { maxConcurrent: 8 },
|
||||
subagents: { maxConcurrent: 8, delegationMode: "prefer" },
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
|
||||
@@ -10,6 +10,20 @@ OpenClaw builds a custom system prompt for every agent run. The prompt is **Open
|
||||
|
||||
The prompt is assembled by OpenClaw and injected into each agent run.
|
||||
|
||||
Prompt assembly has three layers:
|
||||
|
||||
- `buildAgentSystemPrompt` renders the prompt from explicit inputs. It should
|
||||
stay a pure renderer and should not read global config directly.
|
||||
- `resolveAgentSystemPromptConfig` resolves config-backed prompt knobs such as
|
||||
owner display, TTS hints, model aliases, memory citation mode, and sub-agent
|
||||
delegation mode for a specific agent.
|
||||
- Runtime adapters (embedded, CLI, command/export previews, compaction) gather
|
||||
live facts such as tools, sandbox state, channel capabilities, context files,
|
||||
and provider prompt contributions, then call the configured prompt facade.
|
||||
|
||||
This keeps exported/debug prompt surfaces aligned with live runs without
|
||||
turning every runtime-specific detail into one monolithic builder.
|
||||
|
||||
Provider plugins can contribute cache-aware prompt guidance without replacing
|
||||
the full OpenClaw-owned prompt. The provider runtime can:
|
||||
|
||||
@@ -77,6 +91,13 @@ The Tooling section also includes runtime guidance for long-running work:
|
||||
- do not poll `subagents list` / `sessions_list` in a loop just to wait for
|
||||
completion
|
||||
|
||||
`agents.defaults.subagents.delegationMode` can strengthen this guidance. The
|
||||
default `suggest` mode keeps the baseline nudge. `prefer` adds a dedicated
|
||||
**Sub-Agent Delegation** section telling the main agent to act as a responsive
|
||||
coordinator and push anything more involved than a direct reply through
|
||||
`sessions_spawn`. This is prompt-only; tool policy still controls whether
|
||||
`sessions_spawn` is available.
|
||||
|
||||
When the experimental `update_plan` tool is enabled, Tooling also tells the
|
||||
model to use it only for non-trivial multi-step work, keep exactly one
|
||||
`in_progress` step, and avoid repeating the whole plan after each update.
|
||||
|
||||
@@ -143,6 +143,34 @@ session to confirm the effective tool list.
|
||||
- **Thinking:** inherits the caller unless you set `agents.defaults.subagents.thinking` (or per-agent `agents.list[].subagents.thinking`); an explicit `sessions_spawn.thinking` still wins.
|
||||
- **Run timeout:** if `sessions_spawn.runTimeoutSeconds` is omitted, OpenClaw uses `agents.defaults.subagents.runTimeoutSeconds` when set; otherwise it falls back to `0` (no timeout).
|
||||
|
||||
### Delegation prompt mode
|
||||
|
||||
`agents.defaults.subagents.delegationMode` controls prompt guidance only; it does not change tool policy or enforce delegation.
|
||||
|
||||
- `suggest` (default): keep the standard prompt nudge to use sub-agents for larger or slower work.
|
||||
- `prefer`: tell the main agent to stay responsive and delegate anything more involved than a direct reply through `sessions_spawn`.
|
||||
|
||||
Per-agent overrides use `agents.list[].subagents.delegationMode`.
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
maxConcurrent: 4,
|
||||
},
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "coordinator",
|
||||
subagents: { delegationMode: "prefer" },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Tool parameters
|
||||
|
||||
<ParamField path="task" type="string" required>
|
||||
|
||||
25
src/agents/cli-runner/helpers.system-prompt.test.ts
Normal file
25
src/agents/cli-runner/helpers.system-prompt.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildCliAgentSystemPrompt } from "./helpers.js";
|
||||
|
||||
describe("buildCliAgentSystemPrompt", () => {
|
||||
it("uses config-backed sub-agent delegation mode", () => {
|
||||
const prompt = buildCliAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
agentId: "main",
|
||||
tools: [{ name: "sessions_spawn" } as never],
|
||||
modelDisplay: "test/model",
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Sub-Agent Delegation");
|
||||
expect(prompt).toContain("Mode: prefer");
|
||||
});
|
||||
});
|
||||
@@ -19,17 +19,14 @@ import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalLowercaseString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { buildTtsSystemPromptHint } from "../../tts/tts.js";
|
||||
import { buildModelAliasLines } from "../model-alias-lines.js";
|
||||
import { resolveDefaultModelForAgent } from "../model-selection.js";
|
||||
import { resolveOwnerDisplaySetting } from "../owner-display.js";
|
||||
import type { EmbeddedContextFile } from "../pi-embedded-helpers.js";
|
||||
import { detectImageReferences, loadImageFromRef } from "../pi-embedded-runner/run/images.js";
|
||||
import type { SandboxFsBridge } from "../sandbox/fs-bridge.js";
|
||||
import { detectRuntimeShell } from "../shell-utils.js";
|
||||
import { stripSystemPromptCacheBoundary } from "../system-prompt-cache-boundary.js";
|
||||
import { buildConfiguredAgentSystemPrompt } from "../system-prompt-config.js";
|
||||
import { buildSystemPromptParams } from "../system-prompt-params.js";
|
||||
import { buildAgentSystemPrompt } from "../system-prompt.js";
|
||||
import type { SilentReplyPromptMode } from "../system-prompt.types.js";
|
||||
import { sanitizeImageBlocks } from "../tool-images.js";
|
||||
import { formatTomlConfigOverride } from "./toml-inline.js";
|
||||
@@ -68,7 +65,7 @@ export function resolveCliRunQueueKey(params: {
|
||||
return params.backendId;
|
||||
}
|
||||
|
||||
export function buildSystemPrompt(params: {
|
||||
export function buildCliAgentSystemPrompt(params: {
|
||||
workspaceDir: string;
|
||||
config?: OpenClawConfig;
|
||||
defaultThinkLevel?: ThinkLevel;
|
||||
@@ -105,19 +102,15 @@ export function buildSystemPrompt(params: {
|
||||
shell: detectRuntimeShell(),
|
||||
},
|
||||
});
|
||||
const ttsHint = params.config
|
||||
? buildTtsSystemPromptHint(params.config, params.agentId)
|
||||
: undefined;
|
||||
const ownerDisplay = resolveOwnerDisplaySetting(params.config);
|
||||
return buildAgentSystemPrompt({
|
||||
return buildConfiguredAgentSystemPrompt({
|
||||
config: params.config,
|
||||
agentId: params.agentId,
|
||||
workspaceDir: params.workspaceDir,
|
||||
defaultThinkLevel: params.defaultThinkLevel,
|
||||
extraSystemPrompt: params.extraSystemPrompt,
|
||||
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
||||
silentReplyPromptMode: params.silentReplyPromptMode,
|
||||
ownerNumbers: params.ownerNumbers,
|
||||
ownerDisplay: ownerDisplay.ownerDisplay,
|
||||
ownerDisplaySecret: ownerDisplay.ownerDisplaySecret,
|
||||
reasoningTagHint: false,
|
||||
heartbeatPrompt: params.heartbeatPrompt,
|
||||
docsPath: params.docsPath,
|
||||
@@ -125,17 +118,16 @@ export function buildSystemPrompt(params: {
|
||||
acpEnabled: isAcpRuntimeSpawnAvailable({ config: params.config }),
|
||||
runtimeInfo,
|
||||
toolNames: params.tools.map((tool) => tool.name),
|
||||
modelAliasLines: buildModelAliasLines(params.config),
|
||||
skillsPrompt: params.skillsPrompt,
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat,
|
||||
contextFiles: params.contextFiles,
|
||||
ttsHint,
|
||||
memoryCitationsMode: params.config?.memory?.citations,
|
||||
});
|
||||
}
|
||||
|
||||
export const buildSystemPrompt = buildCliAgentSystemPrompt;
|
||||
|
||||
export function normalizeCliModel(modelId: string, backend: CliBackendConfig): string {
|
||||
const trimmed = modelId.trim();
|
||||
if (!trimmed) {
|
||||
|
||||
@@ -46,7 +46,7 @@ import { buildSystemPromptReport } from "../system-prompt-report.js";
|
||||
import { appendModelIdentitySystemPrompt } from "../system-prompt.js";
|
||||
import { redactRunIdentifier, resolveRunWorkspaceDir } from "../workspace-run.js";
|
||||
import { prepareCliBundleMcpConfig } from "./bundle-mcp.js";
|
||||
import { buildSystemPrompt, normalizeCliModel } from "./helpers.js";
|
||||
import { buildCliAgentSystemPrompt, normalizeCliModel } from "./helpers.js";
|
||||
import { cliBackendLog } from "./log.js";
|
||||
import {
|
||||
buildCliSessionHistoryPrompt,
|
||||
@@ -334,7 +334,7 @@ export async function prepareCliRunContext(
|
||||
config: params.config,
|
||||
agentId: sessionAgentId,
|
||||
}) ??
|
||||
buildSystemPrompt({
|
||||
buildCliAgentSystemPrompt({
|
||||
workspaceDir,
|
||||
config: params.config,
|
||||
defaultThinkLevel: params.thinkLevel,
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
transformProviderSystemPrompt,
|
||||
} from "../../plugins/provider-runtime.js";
|
||||
import { isCronSessionKey, isSubagentSessionKey } from "../../routing/session-key.js";
|
||||
import { buildTtsSystemPromptHint } from "../../tts/tts.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import { normalizeMessageChannel } from "../../utils/message-channel.js";
|
||||
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
|
||||
@@ -69,7 +68,6 @@ import {
|
||||
import { isFallbackSummaryError, runWithModelFallback } from "../model-fallback.js";
|
||||
import { supportsModelTools } from "../model-tool-support.js";
|
||||
import { ensureOpenClawModelsJson } from "../models-config.js";
|
||||
import { resolveOwnerDisplaySetting } from "../owner-display.js";
|
||||
import { createBundleLspToolRuntime } from "../pi-bundle-lsp-runtime.js";
|
||||
import { createBundleMcpToolRuntime } from "../pi-bundle-mcp-tools.js";
|
||||
import { ensureSessionHeader } from "../pi-embedded-helpers.js";
|
||||
@@ -140,7 +138,7 @@ import { log } from "./logger.js";
|
||||
import { hardenManualCompactionBoundary } from "./manual-compaction-boundary.js";
|
||||
import { buildEmbeddedMessageActionDiscoveryInput } from "./message-action-discovery-input.js";
|
||||
import { readPiModelContextTokens } from "./model-context-tokens.js";
|
||||
import { buildModelAliasLines, resolveModelAsync } from "./model.js";
|
||||
import { resolveModelAsync } from "./model.js";
|
||||
import { sanitizeSessionHistory, validateReplayTurns } from "./replay-history.js";
|
||||
import { buildEmbeddedSandboxInfo } from "./sandbox-info.js";
|
||||
import { prewarmSessionFile, trackSessionManagerAccess } from "./session-manager-cache.js";
|
||||
@@ -859,10 +857,6 @@ async function compactEmbeddedPiSessionDirectOnce(
|
||||
cwd: effectiveWorkspace,
|
||||
moduleUrl: import.meta.url,
|
||||
});
|
||||
const ttsHint = params.config
|
||||
? buildTtsSystemPromptHint(params.config, sessionAgentId)
|
||||
: undefined;
|
||||
const ownerDisplay = resolveOwnerDisplaySetting(params.config);
|
||||
const promptContributionContext: Parameters<
|
||||
AgentRuntimePlan["prompt"]["resolveSystemPromptContribution"]
|
||||
>[0] = {
|
||||
@@ -885,13 +879,13 @@ async function compactEmbeddedPiSessionDirectOnce(
|
||||
agentId: sessionAgentId,
|
||||
}) ??
|
||||
buildEmbeddedSystemPrompt({
|
||||
config: params.config,
|
||||
agentId: sessionAgentId,
|
||||
workspaceDir: effectiveWorkspace,
|
||||
defaultThinkLevel,
|
||||
reasoningLevel: params.reasoningLevel ?? "off",
|
||||
extraSystemPrompt: params.extraSystemPrompt,
|
||||
ownerNumbers: params.ownerNumbers,
|
||||
ownerDisplay: ownerDisplay.ownerDisplay,
|
||||
ownerDisplaySecret: ownerDisplay.ownerDisplaySecret,
|
||||
reasoningTagHint,
|
||||
heartbeatPrompt: resolveHeartbeatPromptForSystemPrompt({
|
||||
config: params.config,
|
||||
@@ -901,7 +895,6 @@ async function compactEmbeddedPiSessionDirectOnce(
|
||||
skillsPrompt,
|
||||
docsPath: openClawReferences.docsPath ?? undefined,
|
||||
sourcePath: openClawReferences.sourcePath ?? undefined,
|
||||
ttsHint,
|
||||
promptMode,
|
||||
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
||||
acpEnabled: isAcpRuntimeSpawnAvailable({
|
||||
@@ -913,12 +906,10 @@ async function compactEmbeddedPiSessionDirectOnce(
|
||||
messageToolHints,
|
||||
sandboxInfo,
|
||||
tools: effectiveTools,
|
||||
modelAliasLines: buildModelAliasLines(params.config),
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat,
|
||||
contextFiles,
|
||||
memoryCitationsMode: params.config?.memory?.citations,
|
||||
promptContribution,
|
||||
});
|
||||
return createSystemPromptOverride(
|
||||
|
||||
@@ -56,7 +56,6 @@ import {
|
||||
createTrajectoryRuntimeRecorder,
|
||||
toTrajectoryToolDefinitions,
|
||||
} from "../../../trajectory/runtime.js";
|
||||
import { buildTtsSystemPromptHint } from "../../../tts/tts.js";
|
||||
import { resolveUserPath } from "../../../utils.js";
|
||||
import { normalizeMessageChannel } from "../../../utils/message-channel.js";
|
||||
import { isReasoningTagProvider } from "../../../utils/provider-utils.js";
|
||||
@@ -90,11 +89,9 @@ import { isTimeoutError } from "../../failover-error.js";
|
||||
import { resolveHeartbeatPromptForSystemPrompt } from "../../heartbeat-system-prompt.js";
|
||||
import { resolveImageSanitizationLimits } from "../../image-sanitization.js";
|
||||
import { stripHistoricalRuntimeContextCustomMessages } from "../../internal-runtime-context.js";
|
||||
import { buildModelAliasLines } from "../../model-alias-lines.js";
|
||||
import { resolveModelAuthMode } from "../../model-auth.js";
|
||||
import { resolveDefaultModelForAgent } from "../../model-selection.js";
|
||||
import { supportsModelTools } from "../../model-tool-support.js";
|
||||
import { resolveOwnerDisplaySetting } from "../../owner-display.js";
|
||||
import { createBundleLspToolRuntime } from "../../pi-bundle-lsp-runtime.js";
|
||||
import {
|
||||
getOrCreateSessionMcpRuntime,
|
||||
@@ -1253,10 +1250,6 @@ export async function runEmbeddedAttempt(
|
||||
cwd: effectiveWorkspace,
|
||||
moduleUrl: import.meta.url,
|
||||
});
|
||||
const ttsHint = params.config
|
||||
? buildTtsSystemPromptHint(params.config, sessionAgentId)
|
||||
: undefined;
|
||||
const ownerDisplay = resolveOwnerDisplaySetting(params.config);
|
||||
const heartbeatPrompt = shouldInjectHeartbeatPrompt({
|
||||
config: params.config,
|
||||
agentId: sessionAgentId,
|
||||
@@ -1303,19 +1296,18 @@ export async function runEmbeddedAttempt(
|
||||
systemPromptOverrideText,
|
||||
transformProviderSystemPrompt,
|
||||
embeddedSystemPrompt: {
|
||||
config: params.config,
|
||||
agentId: sessionAgentId,
|
||||
workspaceDir: effectiveWorkspace,
|
||||
defaultThinkLevel: params.thinkLevel,
|
||||
reasoningLevel: params.reasoningLevel ?? "off",
|
||||
extraSystemPrompt: params.extraSystemPrompt,
|
||||
ownerNumbers: params.ownerNumbers,
|
||||
ownerDisplay: ownerDisplay.ownerDisplay,
|
||||
ownerDisplaySecret: ownerDisplay.ownerDisplaySecret,
|
||||
reasoningTagHint,
|
||||
heartbeatPrompt,
|
||||
skillsPrompt: effectiveSkillsPrompt,
|
||||
docsPath: openClawReferences.docsPath ?? undefined,
|
||||
sourcePath: openClawReferences.sourcePath ?? undefined,
|
||||
ttsHint,
|
||||
workspaceNotes: workspaceNotes?.length ? workspaceNotes : undefined,
|
||||
reactionGuidance,
|
||||
promptMode: effectivePromptMode,
|
||||
@@ -1330,7 +1322,6 @@ export async function runEmbeddedAttempt(
|
||||
messageToolHints,
|
||||
sandboxInfo,
|
||||
tools: effectiveTools,
|
||||
modelAliasLines: buildModelAliasLines(params.config),
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat,
|
||||
@@ -1338,7 +1329,6 @@ export async function runEmbeddedAttempt(
|
||||
bootstrapMode,
|
||||
bootstrapTruncationNotice,
|
||||
includeMemorySection: !activeContextEngine || activeContextEngine.info.id === "legacy",
|
||||
memoryCitationsMode: params.config?.memory?.citations,
|
||||
promptContribution,
|
||||
},
|
||||
providerTransform: {
|
||||
|
||||
@@ -95,6 +95,37 @@ describe("buildEmbeddedSystemPrompt", () => {
|
||||
expect(prompt).toContain("## Embedded Stable\n\nStable provider guidance.");
|
||||
});
|
||||
|
||||
it("uses config-backed sub-agent delegation mode", () => {
|
||||
const prompt = buildEmbeddedSystemPrompt({
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
agentId: "main",
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
reasoningTagHint: false,
|
||||
runtimeInfo: {
|
||||
agentId: "main",
|
||||
host: "local",
|
||||
os: "darwin",
|
||||
arch: "arm64",
|
||||
node: process.version,
|
||||
model: "gpt-5.4",
|
||||
provider: "openai",
|
||||
},
|
||||
tools: [{ name: "sessions_spawn" } as never],
|
||||
userTimezone: "UTC",
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Sub-Agent Delegation");
|
||||
expect(prompt).toContain("Mode: prefer");
|
||||
});
|
||||
|
||||
it("can omit base memory guidance for non-legacy context engines", () => {
|
||||
registerMemoryPromptSection(() => ["## Memory Recall", "Use memory carefully.", ""]);
|
||||
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
||||
import type { AgentSession } from "@mariozechner/pi-coding-agent";
|
||||
import type { SourceReplyDeliveryMode } from "../../auto-reply/get-reply-options.types.js";
|
||||
import type { SubagentDelegationMode } from "../../config/types.agent-defaults.js";
|
||||
import type { MemoryCitationsMode } from "../../config/types.memory.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { BootstrapMode } from "../bootstrap-mode.js";
|
||||
import type { ResolvedTimeFormat } from "../date-time.js";
|
||||
import type { EmbeddedContextFile } from "../pi-embedded-helpers.js";
|
||||
import { buildConfiguredAgentSystemPrompt } from "../system-prompt-config.js";
|
||||
import type { ProviderSystemPromptContribution } from "../system-prompt-contribution.js";
|
||||
import { buildAgentSystemPrompt } from "../system-prompt.js";
|
||||
import type { PromptMode, SilentReplyPromptMode } from "../system-prompt.types.js";
|
||||
import type { EmbeddedSandboxInfo } from "./types.js";
|
||||
import type { ReasoningLevel, ThinkLevel } from "./utils.js";
|
||||
|
||||
export function buildEmbeddedSystemPrompt(params: {
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
workspaceDir: string;
|
||||
defaultThinkLevel?: ThinkLevel;
|
||||
reasoningLevel?: ReasoningLevel;
|
||||
@@ -35,6 +39,8 @@ export function buildEmbeddedSystemPrompt(params: {
|
||||
/** Controls the generic silent-reply section. Channel-aware prompts can set "none". */
|
||||
silentReplyPromptMode?: SilentReplyPromptMode;
|
||||
sourceReplyDeliveryMode?: SourceReplyDeliveryMode;
|
||||
/** Prompt-only strength for delegating non-trivial work through sub-agents. */
|
||||
subagentDelegationMode?: SubagentDelegationMode;
|
||||
/** Whether ACP-specific routing guidance should be included. Defaults to true. */
|
||||
acpEnabled?: boolean;
|
||||
/** Registered runtime slash/native command names such as `codex`. */
|
||||
@@ -57,7 +63,7 @@ export function buildEmbeddedSystemPrompt(params: {
|
||||
messageToolHints?: string[];
|
||||
sandboxInfo?: EmbeddedSandboxInfo;
|
||||
tools: AgentTool[];
|
||||
modelAliasLines: string[];
|
||||
modelAliasLines?: string[];
|
||||
userTimezone: string;
|
||||
userTime?: string;
|
||||
userTimeFormat?: ResolvedTimeFormat;
|
||||
@@ -68,7 +74,9 @@ export function buildEmbeddedSystemPrompt(params: {
|
||||
memoryCitationsMode?: MemoryCitationsMode;
|
||||
promptContribution?: ProviderSystemPromptContribution;
|
||||
}): string {
|
||||
return buildAgentSystemPrompt({
|
||||
return buildConfiguredAgentSystemPrompt({
|
||||
config: params.config,
|
||||
agentId: params.agentId ?? params.runtimeInfo.agentId,
|
||||
workspaceDir: params.workspaceDir,
|
||||
defaultThinkLevel: params.defaultThinkLevel,
|
||||
reasoningLevel: params.reasoningLevel,
|
||||
@@ -87,6 +95,7 @@ export function buildEmbeddedSystemPrompt(params: {
|
||||
promptMode: params.promptMode,
|
||||
silentReplyPromptMode: params.silentReplyPromptMode,
|
||||
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
||||
subagentDelegationMode: params.subagentDelegationMode,
|
||||
acpEnabled: params.acpEnabled,
|
||||
nativeCommandNames: params.nativeCommandNames,
|
||||
nativeCommandGuidanceLines: params.nativeCommandGuidanceLines,
|
||||
|
||||
74
src/agents/system-prompt-config.test.ts
Normal file
74
src/agents/system-prompt-config.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
buildConfiguredAgentSystemPrompt,
|
||||
resolveAgentSystemPromptConfig,
|
||||
} from "./system-prompt-config.js";
|
||||
|
||||
describe("resolveAgentSystemPromptConfig", () => {
|
||||
it("defaults sub-agent delegation mode to suggest", () => {
|
||||
expect(resolveAgentSystemPromptConfig({ config: {} }).subagentDelegationMode).toBe("suggest");
|
||||
});
|
||||
|
||||
it("inherits default sub-agent delegation mode", () => {
|
||||
const config = {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
|
||||
expect(resolveAgentSystemPromptConfig({ config, agentId: "main" })).toMatchObject({
|
||||
subagentDelegationMode: "prefer",
|
||||
});
|
||||
});
|
||||
|
||||
it("lets per-agent sub-agent delegation mode override defaults", () => {
|
||||
const config = {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "suggest",
|
||||
},
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "coordinator",
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
|
||||
expect(resolveAgentSystemPromptConfig({ config, agentId: "coordinator" })).toMatchObject({
|
||||
subagentDelegationMode: "prefer",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildConfiguredAgentSystemPrompt", () => {
|
||||
it("applies config-backed prompt parameters through the canonical facade", () => {
|
||||
const prompt = buildConfiguredAgentSystemPrompt({
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
agentId: "main",
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
toolNames: ["sessions_spawn", "subagents"],
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Sub-Agent Delegation");
|
||||
expect(prompt).toContain("Mode: prefer");
|
||||
});
|
||||
});
|
||||
53
src/agents/system-prompt-config.ts
Normal file
53
src/agents/system-prompt-config.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { buildTtsSystemPromptHint } from "../tts/tts.js";
|
||||
import { resolveAgentConfig } from "./agent-scope.js";
|
||||
import { buildModelAliasLines } from "./model-alias-lines.js";
|
||||
import { resolveOwnerDisplaySetting } from "./owner-display.js";
|
||||
import { buildAgentSystemPrompt } from "./system-prompt.js";
|
||||
|
||||
type AgentSystemPromptRenderParams = Parameters<typeof buildAgentSystemPrompt>[0];
|
||||
|
||||
export type ResolvedAgentSystemPromptConfig = Pick<
|
||||
AgentSystemPromptRenderParams,
|
||||
| "ownerDisplay"
|
||||
| "ownerDisplaySecret"
|
||||
| "subagentDelegationMode"
|
||||
| "ttsHint"
|
||||
| "modelAliasLines"
|
||||
| "memoryCitationsMode"
|
||||
>;
|
||||
|
||||
export type ConfiguredAgentSystemPromptParams = AgentSystemPromptRenderParams & {
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
};
|
||||
|
||||
export function resolveAgentSystemPromptConfig(params: {
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
}): ResolvedAgentSystemPromptConfig {
|
||||
const { config, agentId } = params;
|
||||
const ownerDisplay = resolveOwnerDisplaySetting(config);
|
||||
const agentSubagents =
|
||||
config && agentId ? resolveAgentConfig(config, agentId)?.subagents : undefined;
|
||||
return {
|
||||
ownerDisplay: ownerDisplay.ownerDisplay,
|
||||
ownerDisplaySecret: ownerDisplay.ownerDisplaySecret,
|
||||
subagentDelegationMode:
|
||||
agentSubagents?.delegationMode ??
|
||||
config?.agents?.defaults?.subagents?.delegationMode ??
|
||||
"suggest",
|
||||
ttsHint: config ? buildTtsSystemPromptHint(config, agentId) : undefined,
|
||||
modelAliasLines: buildModelAliasLines(config),
|
||||
memoryCitationsMode: config?.memory?.citations,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildConfiguredAgentSystemPrompt(params: ConfiguredAgentSystemPromptParams) {
|
||||
const { config, agentId, ...renderParams } = params;
|
||||
const configParams = config ? resolveAgentSystemPromptConfig({ config, agentId }) : {};
|
||||
return buildAgentSystemPrompt({
|
||||
...renderParams,
|
||||
...configParams,
|
||||
});
|
||||
}
|
||||
@@ -784,6 +784,40 @@ describe("buildAgentSystemPrompt", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("adds stronger sub-agent delegation guidance in prefer mode", () => {
|
||||
const defaultPrompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
toolNames: ["sessions_spawn", "subagents"],
|
||||
});
|
||||
const preferPrompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
toolNames: ["sessions_spawn", "subagents"],
|
||||
subagentDelegationMode: "prefer",
|
||||
});
|
||||
|
||||
expect(defaultPrompt).not.toContain("## Sub-Agent Delegation");
|
||||
expect(preferPrompt).toContain("## Sub-Agent Delegation");
|
||||
expect(preferPrompt).toContain("Mode: prefer");
|
||||
expect(preferPrompt).toContain("responsive coordinator");
|
||||
expect(preferPrompt).toContain(
|
||||
"Anything requiring more work than a direct reply should go through `sessions_spawn`",
|
||||
);
|
||||
expect(preferPrompt).toContain(
|
||||
"Use `subagents(action=list|steer|kill)` only when explicitly asked for status",
|
||||
);
|
||||
});
|
||||
|
||||
it("omits prefer delegation guidance when sessions_spawn is unavailable", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
toolNames: ["subagents"],
|
||||
subagentDelegationMode: "prefer",
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("## Sub-Agent Delegation");
|
||||
expect(prompt).toContain("Sub-agent orchestration");
|
||||
});
|
||||
|
||||
it("reapplies provider prompt contributions", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
hasNativeApprovalPromptRuntimeCapability,
|
||||
isKnownNativeApprovalPromptChannel,
|
||||
} from "../channels/plugins/native-approval-prompt.js";
|
||||
import type { SubagentDelegationMode } from "../config/types.agent-defaults.js";
|
||||
import type { MemoryCitationsMode } from "../config/types.memory.js";
|
||||
import { buildMemoryPromptSection } from "../plugins/memory-state.js";
|
||||
import {
|
||||
@@ -63,6 +64,34 @@ type StablePromptPrefixCacheEntry = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
function normalizeSubagentDelegationMode(mode?: SubagentDelegationMode): SubagentDelegationMode {
|
||||
return mode === "prefer" ? "prefer" : "suggest";
|
||||
}
|
||||
|
||||
function buildSubagentDelegationPreferenceSection(params: {
|
||||
mode: SubagentDelegationMode;
|
||||
isMinimal: boolean;
|
||||
hasSessionsSpawn: boolean;
|
||||
hasSubagents: boolean;
|
||||
}): string[] {
|
||||
if (params.isMinimal || params.mode !== "prefer" || !params.hasSessionsSpawn) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
"## Sub-Agent Delegation",
|
||||
"Mode: prefer. You are the responsive coordinator for this conversation.",
|
||||
"- Reply directly only for trivial chat, clarifying questions, or a short answer already known from current context.",
|
||||
"- Anything requiring more work than a direct reply should go through `sessions_spawn`; avoid doing expensive tool calls yourself.",
|
||||
"- Delegate file/code inspection, shell commands, web/browser use, long reads, debugging, coding, multi-step analysis, comparisons, non-trivial summarization, and background waiting.",
|
||||
'- Give the child a clear task. Omit `context` for isolated children; set `context:"fork"` only when current transcript details matter.',
|
||||
"- After spawning, do not poll for completion. Child completion is push-based and returns as a runtime event; synthesize that result for the user.",
|
||||
params.hasSubagents
|
||||
? "- Use `subagents(action=list|steer|kill)` only when explicitly asked for status, or when debugging/intervening; never use it in a wait loop."
|
||||
: "",
|
||||
"",
|
||||
].filter(Boolean);
|
||||
}
|
||||
|
||||
const stablePromptPrefixCache = new Map<string, StablePromptPrefixCacheEntry>();
|
||||
|
||||
function cacheStablePromptPrefix(key: string, build: () => string): string {
|
||||
@@ -624,6 +653,8 @@ export function buildAgentSystemPrompt(params: {
|
||||
/** Controls the generic silent-reply section. Channel-aware prompts can set "none". */
|
||||
silentReplyPromptMode?: SilentReplyPromptMode;
|
||||
sourceReplyDeliveryMode?: SourceReplyDeliveryMode;
|
||||
/** Prompt-only strength for delegating non-trivial work through sub-agents. Defaults to "suggest". */
|
||||
subagentDelegationMode?: SubagentDelegationMode;
|
||||
/** Whether ACP-specific routing guidance should be included. Defaults to true. */
|
||||
acpEnabled?: boolean;
|
||||
/** Registered runtime slash/native command names such as `codex`. */
|
||||
@@ -813,6 +844,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
const messageChannelOptions = listDeliverableMessageChannels().join("|");
|
||||
const promptMode = params.promptMode ?? "full";
|
||||
const isMinimal = promptMode === "minimal" || promptMode === "none";
|
||||
const subagentDelegationMode = normalizeSubagentDelegationMode(params.subagentDelegationMode);
|
||||
const sourceMessageToolOnly = params.sourceReplyDeliveryMode === "message_tool_only";
|
||||
const silentReplyPromptMode = sourceMessageToolOnly
|
||||
? "none"
|
||||
@@ -901,6 +933,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
threadBoundAcpSpawnEnabled,
|
||||
sourceMessageToolOnly,
|
||||
silentReplyPromptMode,
|
||||
subagentDelegationMode,
|
||||
sandboxInfo: params.sandboxInfo,
|
||||
displayWorkspaceDir,
|
||||
workspaceGuidance,
|
||||
@@ -967,6 +1000,12 @@ export function buildAgentSystemPrompt(params: {
|
||||
: []),
|
||||
"Do not poll `subagents list` / `sessions_list` in a loop; only check status on-demand (for intervention, debugging, or when explicitly asked).",
|
||||
"",
|
||||
...buildSubagentDelegationPreferenceSection({
|
||||
mode: subagentDelegationMode,
|
||||
isMinimal,
|
||||
hasSessionsSpawn,
|
||||
hasSubagents: availableTools.has("subagents"),
|
||||
}),
|
||||
...buildOverridablePromptSection({
|
||||
override: providerSectionOverrides.interaction_style,
|
||||
fallback: [],
|
||||
|
||||
@@ -237,4 +237,31 @@ describe("resolveCommandsSystemPromptBundle", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("uses config-backed prompt settings for the target agent", async () => {
|
||||
vi.mocked(resolveSandboxRuntimeStatus).mockReturnValue({
|
||||
sandboxed: false,
|
||||
mode: "off",
|
||||
} as never);
|
||||
createOpenClawCodingToolsMock.mockReturnValue([{ name: "sessions_spawn" }] as never);
|
||||
const params = makeParams();
|
||||
params.cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await resolveCommandsSystemPromptBundle(params);
|
||||
|
||||
expect(vi.mocked(buildAgentSystemPrompt)).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
subagentDelegationMode: "prefer",
|
||||
toolNames: ["sessions_spawn"],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,12 +10,11 @@ import { createOpenClawCodingTools } from "../../agents/pi-tools.js";
|
||||
import { resolveSandboxRuntimeStatus } from "../../agents/sandbox.js";
|
||||
import { buildWorkspaceSkillSnapshot } from "../../agents/skills.js";
|
||||
import { getSkillsSnapshotVersion } from "../../agents/skills/refresh-state.js";
|
||||
import { buildConfiguredAgentSystemPrompt } from "../../agents/system-prompt-config.js";
|
||||
import { buildSystemPromptParams } from "../../agents/system-prompt-params.js";
|
||||
import { buildAgentSystemPrompt } from "../../agents/system-prompt.js";
|
||||
import type { WorkspaceBootstrapFile } from "../../agents/workspace.js";
|
||||
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
|
||||
import { listRegisteredPluginAgentPromptGuidance } from "../../plugins/command-registry-state.js";
|
||||
import { buildTtsSystemPromptHint } from "../../tts/tts.js";
|
||||
import type { HandleCommandsParams } from "./commands-types.js";
|
||||
import { resolveRuntimePolicySessionKey } from "./runtime-policy-session-key.js";
|
||||
|
||||
@@ -146,9 +145,9 @@ export async function resolveCommandsSystemPromptBundle(
|
||||
},
|
||||
}
|
||||
: { enabled: false };
|
||||
const ttsHint = params.cfg ? buildTtsSystemPromptHint(params.cfg, sessionAgentId) : undefined;
|
||||
|
||||
const systemPrompt = buildAgentSystemPrompt({
|
||||
const systemPrompt = buildConfiguredAgentSystemPrompt({
|
||||
config: params.cfg,
|
||||
agentId: sessionAgentId,
|
||||
workspaceDir,
|
||||
defaultThinkLevel: params.resolvedThinkLevel,
|
||||
reasoningLevel: params.resolvedReasoningLevel,
|
||||
@@ -156,14 +155,12 @@ export async function resolveCommandsSystemPromptBundle(
|
||||
ownerNumbers: undefined,
|
||||
reasoningTagHint: false,
|
||||
toolNames,
|
||||
modelAliasLines: [],
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat,
|
||||
contextFiles: injectedFiles,
|
||||
skillsPrompt,
|
||||
heartbeatPrompt: undefined,
|
||||
ttsHint,
|
||||
acpEnabled: isAcpRuntimeSpawnAvailable({
|
||||
config: params.cfg,
|
||||
sandboxed: sandboxRuntime.sandboxed,
|
||||
@@ -171,7 +168,6 @@ export async function resolveCommandsSystemPromptBundle(
|
||||
nativeCommandGuidanceLines: listRegisteredPluginAgentPromptGuidance(),
|
||||
runtimeInfo,
|
||||
sandboxInfo,
|
||||
memoryCitationsMode: params.cfg?.memory?.citations,
|
||||
});
|
||||
|
||||
return { systemPrompt, tools, skillsPrompt, bootstrapFiles, injectedFiles, sandboxRuntime };
|
||||
|
||||
@@ -227,6 +227,10 @@ export const FIELD_HELP: Record<string, string> = {
|
||||
"Shared default settings inherited by agents unless overridden per entry in agents.list. Use defaults to enforce consistent baseline behavior and reduce duplicated per-agent configuration.",
|
||||
"agents.defaults.skills":
|
||||
"Optional default skill allowlist inherited by agents that omit agents.list[].skills. Omit for unrestricted skills, set [] to give inheriting agents no skills, and remember explicit agents.list[].skills replaces this default instead of merging with it.",
|
||||
"agents.defaults.subagents.delegationMode":
|
||||
'Prompt-only sub-agent delegation strength. "suggest" keeps the default guidance; "prefer" strongly instructs the main agent to delegate anything more involved than a direct reply via sessions_spawn.',
|
||||
"agents.list[].subagents.delegationMode":
|
||||
"Per-agent override for sub-agent delegation strength. Use this for coordinator agents that should stay responsive and push non-trivial work into spawned sub-agents.",
|
||||
"agents.defaults.contextLimits":
|
||||
"Focused per-agent-context budget defaults for selected high-volume excerpts and injected prompt blocks. Use this to tune bounded read/injection sizes without reopening any unbounded call paths.",
|
||||
"agents.defaults.contextLimits.memoryGetMaxChars":
|
||||
|
||||
@@ -388,6 +388,8 @@ export const FIELD_LABELS: Record<string, string> = {
|
||||
"skills.load.watch": "Watch Skills",
|
||||
"skills.load.watchDebounceMs": "Skills Watch Debounce (ms)",
|
||||
"agents.defaults.skills": "Skills",
|
||||
"agents.defaults.subagents.delegationMode": "Sub-agent Delegation Mode",
|
||||
"agents.list[].subagents.delegationMode": "Sub-agent Delegation Mode",
|
||||
"agents.defaults.workspace": "Workspace",
|
||||
"agents.defaults.repoRoot": "Repo Root",
|
||||
"agents.defaults.promptOverlays": "Prompt Overlays",
|
||||
|
||||
@@ -19,6 +19,7 @@ import type { MemorySearchConfig } from "./types.tools.js";
|
||||
export type AgentContextInjection = "always" | "continuation-skip" | "never";
|
||||
export type OptionalBootstrapFileName = "SOUL.md" | "USER.md" | "HEARTBEAT.md" | "IDENTITY.md";
|
||||
export type EmbeddedPiExecutionContract = "default" | "strict-agentic";
|
||||
export type SubagentDelegationMode = "suggest" | "prefer";
|
||||
|
||||
export type Gpt5PromptOverlayConfig = {
|
||||
/** Friendly interaction-style layer for GPT-5-family models (default: friendly). */
|
||||
@@ -420,6 +421,8 @@ export type AgentDefaultsConfig = {
|
||||
maxConcurrent?: number;
|
||||
/** Sub-agent defaults (spawned via sessions_spawn). */
|
||||
subagents?: {
|
||||
/** Prompt-only guidance for how strongly the main agent should delegate work. Default: "suggest". */
|
||||
delegationMode?: SubagentDelegationMode;
|
||||
/** Default allowlist of target agent ids for sessions_spawn. Use "*" to allow any. */
|
||||
allowAgents?: string[];
|
||||
/** Max concurrent sub-agent runs (global lane: "subagent"). Default: 1. */
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
AgentDefaultsConfig,
|
||||
AgentModelEntryConfig,
|
||||
EmbeddedPiExecutionContract,
|
||||
SubagentDelegationMode,
|
||||
} from "./types.agent-defaults.js";
|
||||
import type {
|
||||
AgentEmbeddedHarnessConfig,
|
||||
@@ -116,6 +117,8 @@ export type AgentConfig = {
|
||||
identity?: IdentityConfig;
|
||||
groupChat?: GroupChatConfig;
|
||||
subagents?: {
|
||||
/** Prompt-only guidance for how strongly this agent should delegate work. */
|
||||
delegationMode?: SubagentDelegationMode;
|
||||
/** Allow spawning sub-agents under other agent ids. Use "*" to allow any. */
|
||||
allowAgents?: string[];
|
||||
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
|
||||
@@ -32,6 +32,32 @@ describe("agent defaults schema", () => {
|
||||
).toMatchObject({ success: true });
|
||||
});
|
||||
|
||||
it("accepts subagent delegation mode on defaults and agent entries", () => {
|
||||
expect(
|
||||
AgentDefaultsSchema.safeParse({
|
||||
subagents: {
|
||||
delegationMode: "prefer",
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ success: true });
|
||||
expect(
|
||||
AgentEntrySchema.safeParse({
|
||||
id: "coordinator",
|
||||
subagents: {
|
||||
delegationMode: "suggest",
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ success: true });
|
||||
expectSchemaFailurePath(
|
||||
AgentDefaultsSchema.safeParse({
|
||||
subagents: {
|
||||
delegationMode: "required",
|
||||
},
|
||||
}),
|
||||
"subagents.delegationMode",
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts videoGenerationModel", () => {
|
||||
expect(
|
||||
AgentDefaultsSchema.safeParse({
|
||||
|
||||
@@ -259,6 +259,7 @@ export const AgentDefaultsSchema = z
|
||||
maxConcurrent: z.number().int().positive().optional(),
|
||||
subagents: z
|
||||
.object({
|
||||
delegationMode: z.enum(["suggest", "prefer"]).optional(),
|
||||
allowAgents: z.array(z.string()).optional(),
|
||||
maxConcurrent: z.number().int().positive().optional(),
|
||||
maxSpawnDepth: z
|
||||
|
||||
@@ -879,6 +879,7 @@ export const AgentEntrySchema = z
|
||||
groupChat: GroupChatSchema,
|
||||
subagents: z
|
||||
.object({
|
||||
delegationMode: z.enum(["suggest", "prefer"]).optional(),
|
||||
allowAgents: z.array(z.string()).optional(),
|
||||
model: z
|
||||
.union([
|
||||
|
||||
Reference in New Issue
Block a user