mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
fix(agents): declare visible-session constraints upfront in sessions_spawn (#111502)
This commit is contained in:
@@ -221,6 +221,7 @@ Per-agent override: `agents.list[].subagents.delegationMode`.
|
||||
<ParamField path="mode" type='"run" | "session"' default="run">
|
||||
If `thread: true` and `mode` is omitted, default becomes `session`. `mode: "session"` requires `thread: true`.
|
||||
If thread binding is unavailable for the requester channel, use `mode: "run"` instead.
|
||||
With `visible: true`, omit `mode`; visible sessions are persistent and do not support `mode: "run"`.
|
||||
</ParamField>
|
||||
<ParamField path="cleanup" type='"delete" | "keep"' default="keep">
|
||||
`"delete"` archives the session immediately after announce (still keeps the transcript via rename).
|
||||
@@ -251,7 +252,7 @@ their latest assistant turn back to the requester; external delivery stays with
|
||||
the parent/requester agent.
|
||||
</Warning>
|
||||
|
||||
With `visible: true`, `model`, `cwd`, and a same-agent `context: "fork"` are supported. A sandboxed target restricts `cwd` to that agent's workspace. Thread binding, `mode`, thinking overrides, light bootstrap context, and attachment staging are unavailable on this path because visible sessions are persistent dashboard sessions created through `sessions.create`. Visible spawning is also rejected when inherited tool restrictions cannot be carried into the dashboard session. See [Managed worktrees](/concepts/managed-worktrees) for checkout naming, setup, cleanup, and restore behavior.
|
||||
With `visible: true`, `model`, `cwd`, and a same-agent `context: "fork"` are supported. A sandboxed target restricts `cwd` to that agent's workspace. Thread binding, `mode`, thinking overrides, `lightContext`, `attachments`, and `attachAs` are unavailable on this path because visible sessions are persistent dashboard sessions created through `sessions.create`. Visible spawning is rejected when the requester was itself spawned with an inherited tool allowlist or denylist; that restriction is fixed at spawn time and has no config override. Session listing and addressing obey `tools.sessions.visibility`; the default `tree` scope covers the current session and its own spawn subtree. See [Managed worktrees](/concepts/managed-worktrees) for checkout naming, setup, cleanup, and restore behavior.
|
||||
|
||||
### Task names and targeting
|
||||
|
||||
|
||||
@@ -72,6 +72,8 @@ export function describeSessionsSpawnTool(options?: {
|
||||
options?.threadAvailable
|
||||
? '`mode="run"` one-shot; `mode="session"` persistent/thread-bound only on supporting requester channel.'
|
||||
: '`mode="run"` one-shot background.',
|
||||
'`visible=true`: persistent dashboard session; subagent only; omit `mode` (no `mode="run"`), `thread`, `thinking`, `lightContext`, `attachments`, `attachAs`; inherited tool allow/denylist blocks it at spawn with no config override.',
|
||||
"Session listing/addressing obeys `tools.sessions.visibility` (`tree` default: current + own spawn subtree).",
|
||||
"Inherits parent workspace. Native task arrives as first `[Subagent Task]`.",
|
||||
'Native transcript needed: `context="fork"`; else omit/isolated.',
|
||||
"Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers.",
|
||||
@@ -81,9 +83,9 @@ export function describeSessionsSpawnTool(options?: {
|
||||
return baseDescription.join(" ");
|
||||
}
|
||||
return [
|
||||
...baseDescription.slice(0, 3),
|
||||
...baseDescription.slice(0, 5),
|
||||
'`runtime="acp"` ids: codex, claude, gemini, opencode, or configured ACP.',
|
||||
...baseDescription.slice(3),
|
||||
...baseDescription.slice(5),
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
|
||||
@@ -382,12 +382,26 @@ describe("sessions_spawn tool", () => {
|
||||
it("advertises visible sessions with terse UI guidance", () => {
|
||||
const tool = createSessionsSpawnTool();
|
||||
const schema = tool.parameters as {
|
||||
properties?: { visible?: { description?: string }; worktree?: unknown };
|
||||
properties?: Record<
|
||||
string,
|
||||
{ anyOf?: unknown; description?: string; enum?: string[] } | undefined
|
||||
>;
|
||||
};
|
||||
|
||||
expect(schema.properties?.visible?.description).toBe(
|
||||
"visible: user sees session in UI. Use when user asked or talks via web/app.",
|
||||
"Persistent UI session; subagent only; omit mode/thread/thinking/lightContext/attachments/attachAs; unavailable with inherited tool allow/denylist.",
|
||||
);
|
||||
expect(tool.description).toContain("`visible=true`: persistent dashboard session");
|
||||
expect(tool.description).toContain('no `mode="run"`');
|
||||
expect(tool.description).toContain("inherited tool allow/denylist");
|
||||
expect(tool.description).toContain("`tools.sessions.visibility`");
|
||||
expect(schema.properties?.runtime?.description).toContain("visible=true");
|
||||
expect(schema.properties?.mode?.description).toContain("Omit with visible=true");
|
||||
expect(schema.properties?.lightContext?.description).toContain("unavailable with visible=true");
|
||||
expect(schema.properties?.attachments?.description).toContain("unavailable with visible=true");
|
||||
expect(schema.properties?.attachAs?.description).toContain("unavailable with visible=true");
|
||||
expect(schema.properties?.mode?.enum).toEqual(["run"]);
|
||||
expect(schema.properties?.mode?.anyOf).toBeUndefined();
|
||||
expect(schema.properties?.worktree).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -477,7 +491,7 @@ describe("sessions_spawn tool", () => {
|
||||
|
||||
await expect(
|
||||
tool.execute("hidden-worktree", { task: "inspect", worktree: true }),
|
||||
).rejects.toThrow("worktree options require visible=true");
|
||||
).rejects.toThrow("Parameters require visible=true: worktree");
|
||||
expect(hoisted.spawnSubagentDirectMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -616,32 +630,32 @@ describe("sessions_spawn tool", () => {
|
||||
[
|
||||
"thinking",
|
||||
{ thinking: "high" },
|
||||
"thinking unavailable with visible=true: thinking overrides are not wired to the sessions.create path",
|
||||
"Parameters unavailable with visible=true: thinking: thinking overrides are not wired to the sessions.create path",
|
||||
],
|
||||
[
|
||||
"thread",
|
||||
{ thread: true },
|
||||
"thread unavailable with visible=true: visible sessions route to the dashboard, not a channel thread",
|
||||
"Parameters unavailable with visible=true: thread: visible sessions route to the dashboard, not a channel thread",
|
||||
],
|
||||
[
|
||||
"mode",
|
||||
{ mode: "session" },
|
||||
"mode unavailable with visible=true: visible sessions are persistent dashboard sessions",
|
||||
"Parameters unavailable with visible=true: mode: visible sessions are persistent dashboard sessions",
|
||||
],
|
||||
[
|
||||
"lightContext",
|
||||
{ lightContext: true },
|
||||
"lightContext unavailable with visible=true: bootstrap staging is not wired to the sessions.create path",
|
||||
"Parameters unavailable with visible=true: lightContext: bootstrap staging is not wired to the sessions.create path",
|
||||
],
|
||||
[
|
||||
"attachments",
|
||||
{ attachments: [{ name: "note.txt", content: "hello" }] },
|
||||
"attachments unavailable with visible=true: attachment staging is not wired to the sessions.create path",
|
||||
"Parameters unavailable with visible=true: attachments: attachment staging is not wired to the sessions.create path",
|
||||
],
|
||||
[
|
||||
"attachAs",
|
||||
{ attachAs: { mountPath: "inputs" } },
|
||||
"attachAs unavailable with visible=true: attachment staging is not wired to the sessions.create path",
|
||||
"Parameters unavailable with visible=true: attachAs: attachment staging is not wired to the sessions.create path",
|
||||
],
|
||||
] as const)("rejects visible %s overrides with a reason", async (_name, override, message) => {
|
||||
const tool = createSessionsSpawnTool({ agentSessionKey: "agent:main:main" });
|
||||
@@ -651,6 +665,26 @@ describe("sessions_spawn tool", () => {
|
||||
).rejects.toThrow(message);
|
||||
});
|
||||
|
||||
it("reports every unsupported visible parameter in one error", async () => {
|
||||
const tool = createSessionsSpawnTool({ agentSessionKey: "agent:main:main" });
|
||||
|
||||
await expect(
|
||||
tool.execute("visible-unsupported-many", {
|
||||
task: "inspect",
|
||||
runtime: "acp",
|
||||
thinking: "high",
|
||||
thread: true,
|
||||
mode: "run",
|
||||
lightContext: true,
|
||||
attachments: [{ name: "note.txt", content: "hello" }],
|
||||
attachAs: { mountPath: "inputs" },
|
||||
visible: true,
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
'Parameters unavailable with visible=true: runtime: supports runtime="subagent" only; thinking: thinking overrides are not wired to the sessions.create path; thread: visible sessions route to the dashboard, not a channel thread; mode: visible sessions are persistent dashboard sessions; lightContext: bootstrap staging is not wired to the sessions.create path; attachments: attachment staging is not wired to the sessions.create path; attachAs: attachment staging is not wired to the sessions.create path',
|
||||
);
|
||||
});
|
||||
|
||||
it("denies visible sessions when tool restrictions cannot carry forward", async () => {
|
||||
const callGateway = vi.fn();
|
||||
const tool = createSessionsSpawnTool({
|
||||
@@ -667,7 +701,8 @@ describe("sessions_spawn tool", () => {
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
status: "forbidden",
|
||||
error: "Visible sessions unavailable with inherited tool restrictions.",
|
||||
error:
|
||||
"Visible sessions unavailable with inherited tool restrictions. This session was spawned with a tool allow/denylist; visible sessions require an unrestricted session.",
|
||||
});
|
||||
expect(callGateway).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -143,29 +143,40 @@ function createSessionsSpawnToolSchema(params: {
|
||||
label: Type.Optional(Type.String()),
|
||||
runtime: optionalStringEnum(
|
||||
params.acpAvailable ? SESSIONS_SPAWN_RUNTIMES : (["subagent"] as const),
|
||||
{ description: 'Runtime; visible=true requires "subagent".' },
|
||||
),
|
||||
agentId: Type.Optional(Type.String()),
|
||||
model: Type.Optional(Type.String()),
|
||||
thinking: Type.Optional(Type.String()),
|
||||
thinking: Type.Optional(
|
||||
Type.String({ description: "Thinking override; unavailable with visible=true." }),
|
||||
),
|
||||
cwd: Type.Optional(Type.String()),
|
||||
...(params.threadAvailable
|
||||
? {
|
||||
thread: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: 'Bind new chat thread when supported; true defaults mode="session".',
|
||||
description:
|
||||
'Bind new chat thread when supported; true defaults mode="session"; unavailable with visible=true.',
|
||||
}),
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
mode: optionalStringEnum(spawnModes),
|
||||
cleanup: optionalStringEnum(["delete", "keep"] as const),
|
||||
mode: optionalStringEnum(spawnModes, {
|
||||
description: params.threadAvailable
|
||||
? '"run" one-shot; "session" persistent/thread-bound. Omit with visible=true.'
|
||||
: '"run" one-shot. Omit with visible=true; visible sessions are persistent.',
|
||||
}),
|
||||
cleanup: optionalStringEnum(["delete", "keep"] as const, {
|
||||
description: "Hidden session cleanup; visible=true always keeps the session.",
|
||||
}),
|
||||
sandbox: optionalStringEnum(SESSIONS_SPAWN_SANDBOX_MODES),
|
||||
context: optionalStringEnum(SUBAGENT_SPAWN_CONTEXT_MODES, {
|
||||
description: "Native: omit/isolated clean; fork only needing requester transcript.",
|
||||
description:
|
||||
"Native: omit/isolated clean; fork only needing requester transcript; visible fork requires same agent.",
|
||||
}),
|
||||
lightContext: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Light bootstrap; subagent only.",
|
||||
description: "Light bootstrap; subagent only; unavailable with visible=true.",
|
||||
}),
|
||||
),
|
||||
...(params.swarmEnabled
|
||||
@@ -187,15 +198,18 @@ function createSessionsSpawnToolSchema(params: {
|
||||
encoding: Type.Optional(optionalStringEnum(["utf8", "base64"] as const)),
|
||||
mimeType: Type.Optional(Type.String()),
|
||||
}),
|
||||
{ maxItems: 50 },
|
||||
{ maxItems: 50, description: "Inline snapshots; unavailable with visible=true." },
|
||||
),
|
||||
),
|
||||
attachAs: Type.Optional(
|
||||
Type.Object({
|
||||
// Where the spawned agent should look for attachments.
|
||||
// Kept as a hint; implementation materializes into the child workspace.
|
||||
mountPath: Type.Optional(Type.String()),
|
||||
}),
|
||||
Type.Object(
|
||||
{
|
||||
// Where the spawned agent should look for attachments.
|
||||
// Kept as a hint; implementation materializes into the child workspace.
|
||||
mountPath: Type.Optional(Type.String()),
|
||||
},
|
||||
{ description: "Attachment mount hint; unavailable with visible=true." },
|
||||
),
|
||||
),
|
||||
...(params.acpAvailable
|
||||
? {
|
||||
|
||||
@@ -30,7 +30,8 @@ import { reserveVisibleChildSlot } from "./sessions-spawn-visible-admission.js";
|
||||
export const VISIBLE_SESSIONS_SPAWN_SCHEMA = {
|
||||
visible: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "visible: user sees session in UI. Use when user asked or talks via web/app.",
|
||||
description:
|
||||
"Persistent UI session; subagent only; omit mode/thread/thinking/lightContext/attachments/attachAs; unavailable with inherited tool allow/denylist.",
|
||||
}),
|
||||
),
|
||||
worktree: Type.Optional(Type.Boolean({ description: "Visible session worktree" })),
|
||||
@@ -94,18 +95,30 @@ export async function maybeSpawnVisibleSession(params: {
|
||||
const worktreeName = readStringParam(params.raw, "worktreeName");
|
||||
const worktreeBaseRef = readStringParam(params.raw, "worktreeBaseRef");
|
||||
if (params.raw.visible !== true) {
|
||||
if (worktree || worktreeName || worktreeBaseRef) {
|
||||
throw new ToolInputError("worktree options require visible=true");
|
||||
const visibleOnlyParams = [
|
||||
["worktree", worktree],
|
||||
["worktreeName", worktreeName],
|
||||
["worktreeBaseRef", worktreeBaseRef],
|
||||
] as const;
|
||||
const providedVisibleOnlyParams = visibleOnlyParams
|
||||
.filter(([, value]) => value !== undefined && value !== false)
|
||||
.map(([name]) => name);
|
||||
if (providedVisibleOnlyParams.length > 0) {
|
||||
throw new ToolInputError(
|
||||
`Parameters require visible=true: ${providedVisibleOnlyParams.join(", ")}`,
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (params.runtime !== "subagent") {
|
||||
throw new ToolInputError('visible=true supports runtime="subagent" only');
|
||||
}
|
||||
const modelOverride = normalizeToolModelOverride(readStringParam(params.raw, "model"));
|
||||
const requestedCwd = readStringParam(params.raw, "cwd");
|
||||
const spawnedCwd = requestedCwd ? resolveUserPath(requestedCwd) : undefined;
|
||||
const unsupported = [
|
||||
[
|
||||
"runtime",
|
||||
params.runtime === "subagent" ? undefined : params.runtime,
|
||||
'supports runtime="subagent" only',
|
||||
],
|
||||
[
|
||||
"thinking",
|
||||
readStringParam(params.raw, "thinking"),
|
||||
@@ -133,10 +146,12 @@ export async function maybeSpawnVisibleSession(params: {
|
||||
"attachment staging is not wired to the sessions.create path",
|
||||
],
|
||||
] as const;
|
||||
const unsupportedEntry = unsupported.find(([, value]) => value !== undefined);
|
||||
if (unsupportedEntry) {
|
||||
const unsupportedEntries = unsupported.filter(([, value]) => value !== undefined);
|
||||
if (unsupportedEntries.length > 0) {
|
||||
throw new ToolInputError(
|
||||
`${unsupportedEntry[0]} unavailable with visible=true: ${unsupportedEntry[2]}`,
|
||||
`Parameters unavailable with visible=true: ${unsupportedEntries
|
||||
.map(([name, , reason]) => `${name}: ${reason}`)
|
||||
.join("; ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -147,7 +162,8 @@ export async function maybeSpawnVisibleSession(params: {
|
||||
) {
|
||||
return {
|
||||
status: "forbidden",
|
||||
error: "Visible sessions unavailable with inherited tool restrictions.",
|
||||
error:
|
||||
"Visible sessions unavailable with inherited tool restrictions. This session was spawned with a tool allow/denylist; visible sessions require an unrestricted session.",
|
||||
};
|
||||
}
|
||||
const ownership = resolveSubagentSpawnOwnership({
|
||||
|
||||
+11
-5
@@ -138,13 +138,14 @@
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot; `mode=\"session\"` persistent/thread-bound only on supporting requester channel. Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work. Run result returns; session output stays thread.",
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot; `mode=\"session\"` persistent/thread-bound only on supporting requester channel. `visible=true`: persistent dashboard session; subagent only; omit `mode` (no `mode=\"run\"`), `thread`, `thinking`, `lightContext`, `attachments`, `attachAs`; inherited tool allow/denylist blocks it at spawn with no config override. Session listing/addressing obeys `tools.sessions.visibility` (`tree` default: current + own spawn subtree). Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work. Run result returns; session output stays thread.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"description": "Attachment mount hint; unavailable with visible=true.",
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
@@ -153,6 +154,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"description": "Inline snapshots; unavailable with visible=true.",
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
@@ -176,11 +178,12 @@
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"description": "Hidden session cleanup; visible=true always keeps the session.",
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript.",
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript; visible fork requires same agent.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -191,10 +194,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap; subagent only.",
|
||||
"description": "Light bootstrap; subagent only; unavailable with visible=true.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"description": "\"run\" one-shot; \"session\" persistent/thread-bound. Omit with visible=true.",
|
||||
"enum": ["run", "session"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -202,6 +206,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"description": "Runtime; visible=true requires \"subagent\".",
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -217,14 +222,15 @@
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"description": "Thinking override; unavailable with visible=true.",
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"description": "Bind new chat thread when supported; true defaults mode=\"session\".",
|
||||
"description": "Bind new chat thread when supported; true defaults mode=\"session\"; unavailable with visible=true.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"visible": {
|
||||
"description": "visible: user sees session in UI. Use when user asked or talks via web/app.",
|
||||
"description": "Persistent UI session; subagent only; omit mode/thread/thinking/lightContext/attachments/attachAs; unavailable with inherited tool allow/denylist.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"worktree": {
|
||||
|
||||
+10
-4
@@ -138,13 +138,14 @@
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background. Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work while run result returns.",
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background. `visible=true`: persistent dashboard session; subagent only; omit `mode` (no `mode=\"run\"`), `thread`, `thinking`, `lightContext`, `attachments`, `attachAs`; inherited tool allow/denylist blocks it at spawn with no config override. Session listing/addressing obeys `tools.sessions.visibility` (`tree` default: current + own spawn subtree). Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work while run result returns.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"description": "Attachment mount hint; unavailable with visible=true.",
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
@@ -153,6 +154,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"description": "Inline snapshots; unavailable with visible=true.",
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
@@ -176,11 +178,12 @@
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"description": "Hidden session cleanup; visible=true always keeps the session.",
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript.",
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript; visible fork requires same agent.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -191,10 +194,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap; subagent only.",
|
||||
"description": "Light bootstrap; subagent only; unavailable with visible=true.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"description": "\"run\" one-shot. Omit with visible=true; visible sessions are persistent.",
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -202,6 +206,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"description": "Runtime; visible=true requires \"subagent\".",
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -217,10 +222,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"description": "Thinking override; unavailable with visible=true.",
|
||||
"type": "string"
|
||||
},
|
||||
"visible": {
|
||||
"description": "visible: user sees session in UI. Use when user asked or talks via web/app.",
|
||||
"description": "Persistent UI session; subagent only; omit mode/thread/thinking/lightContext/attachments/attachAs; unavailable with inherited tool allow/denylist.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"worktree": {
|
||||
|
||||
+10
-4
@@ -138,13 +138,14 @@
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background. Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work while run result returns.",
|
||||
"description": "Spawn clean child; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background. `visible=true`: persistent dashboard session; subagent only; omit `mode` (no `mode=\"run\"`), `thread`, `thinking`, `lightContext`, `attachments`, `attachAs`; inherited tool allow/denylist blocks it at spawn with no config override. Session listing/addressing obeys `tools.sessions.visibility` (`tree` default: current + own spawn subtree). Inherits parent workspace. Native task arrives as first `[Subagent Task]`. Native transcript needed: `context=\"fork\"`; else omit/isolated. Use fresh child for sidecar/parallel batch reads, multi-step search, data collection; avoid quick lookup/single read unless policy prefers. After spawn, do non-overlap work while run result returns.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"description": "Attachment mount hint; unavailable with visible=true.",
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
@@ -153,6 +154,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"description": "Inline snapshots; unavailable with visible=true.",
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
@@ -176,11 +178,12 @@
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"description": "Hidden session cleanup; visible=true always keeps the session.",
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript.",
|
||||
"description": "Native: omit/isolated clean; fork only needing requester transcript; visible fork requires same agent.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -191,10 +194,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap; subagent only.",
|
||||
"description": "Light bootstrap; subagent only; unavailable with visible=true.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"description": "\"run\" one-shot. Omit with visible=true; visible sessions are persistent.",
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -202,6 +206,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"description": "Runtime; visible=true requires \"subagent\".",
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -217,10 +222,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"description": "Thinking override; unavailable with visible=true.",
|
||||
"type": "string"
|
||||
},
|
||||
"visible": {
|
||||
"description": "visible: user sees session in UI. Use when user asked or talks via web/app.",
|
||||
"description": "Persistent UI session; subagent only; omit mode/thread/thinking/lightContext/attachments/attachAs; unavailable with inherited tool allow/denylist.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"worktree": {
|
||||
|
||||
Vendored
+4
-4
@@ -216,8 +216,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 55806,
|
||||
"roughTokens": 13952
|
||||
"chars": 56822,
|
||||
"roughTokens": 14206
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 3559,
|
||||
@@ -228,8 +228,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 7021
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 83892,
|
||||
"roughTokens": 20973
|
||||
"chars": 84908,
|
||||
"roughTokens": 21227
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1442,
|
||||
|
||||
test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-direct-codex-message-tool.md
Vendored
+4
-4
@@ -216,8 +216,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 55533,
|
||||
"roughTokens": 13884
|
||||
"chars": 56514,
|
||||
"roughTokens": 14129
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 2450,
|
||||
@@ -228,8 +228,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 6642
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 82101,
|
||||
"roughTokens": 20526
|
||||
"chars": 83082,
|
||||
"roughTokens": 20771
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1033,
|
||||
|
||||
Vendored
+4
-4
@@ -217,8 +217,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 56823,
|
||||
"roughTokens": 14206
|
||||
"chars": 57804,
|
||||
"roughTokens": 14451
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 2469,
|
||||
@@ -229,8 +229,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 6777
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 83930,
|
||||
"roughTokens": 20983
|
||||
"chars": 84911,
|
||||
"roughTokens": 21228
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1271,
|
||||
|
||||
Reference in New Issue
Block a user