mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix: keep OpenClaw control tools available when tool_search misroutes (#99561)
* fix(codex): keep OpenClaw control tools direct * test(codex): refresh direct-tool prompt snapshots * fix(codex): keep heartbeat direct only when available * fix(codex): keep heartbeat tool schema stable --------- Co-authored-by: Eva <eva@100yen.org> Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
This commit is contained in:
@@ -178,12 +178,13 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("createCodexDynamicToolBridge", () => {
|
||||
it("keeps turn-yield direct while deferring OpenClaw session spawn", () => {
|
||||
it("keeps OpenClaw control-path tools direct while deferring broad tools", () => {
|
||||
const bridge = createCodexDynamicToolBridge({
|
||||
tools: [
|
||||
createTool({ name: "web_search" }),
|
||||
createTool({ name: "message" }),
|
||||
createTool({ name: HEARTBEAT_RESPONSE_TOOL_NAME }),
|
||||
createTool({ name: "agents_list" }),
|
||||
createTool({ name: "sessions_spawn" }),
|
||||
createTool({ name: "sessions_yield" }),
|
||||
],
|
||||
@@ -194,6 +195,7 @@ describe("createCodexDynamicToolBridge", () => {
|
||||
const webSearch = specs.find((tool) => tool.name === "web_search");
|
||||
const message = specs.find((tool) => tool.name === "message");
|
||||
const heartbeat = specs.find((tool) => tool.name === HEARTBEAT_RESPONSE_TOOL_NAME);
|
||||
const agentsList = specs.find((tool) => tool.name === "agents_list");
|
||||
const sessionsSpawn = specs.find((tool) => tool.name === "sessions_spawn");
|
||||
const sessionsYield = specs.find((tool) => tool.name === "sessions_yield");
|
||||
|
||||
@@ -212,11 +214,8 @@ describe("createCodexDynamicToolBridge", () => {
|
||||
namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
|
||||
deferLoading: true,
|
||||
});
|
||||
expectDynamicSpec(sessionsSpawn, {
|
||||
name: "sessions_spawn",
|
||||
namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
|
||||
deferLoading: true,
|
||||
});
|
||||
expectNoNamespace(agentsList);
|
||||
expectNoNamespace(sessionsSpawn);
|
||||
expectNoNamespace(sessionsYield);
|
||||
});
|
||||
|
||||
|
||||
@@ -353,9 +353,14 @@ export type CodexDynamicToolBridge = {
|
||||
/** Namespace attached to OpenClaw-owned dynamic tools exposed to Codex. */
|
||||
export const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
|
||||
|
||||
// Keep OpenClaw session spawning searchable in Codex mode so Codex's native
|
||||
// spawn_agent remains the primary Codex subagent surface.
|
||||
const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
|
||||
// Keep OpenClaw control-path tools directly callable even when Codex tool_search
|
||||
// is unavailable or resolves a connector-only universe. Developer instructions
|
||||
// still steer normal Codex subagents to native spawn_agent.
|
||||
const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set([
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
]);
|
||||
const EXPLICIT_MESSAGE_PROVIDER_KEYS = ["channel", "provider"];
|
||||
const EXPLICIT_MESSAGE_TARGET_KEYS = ["target", "to", "channelId"];
|
||||
const EXPLICIT_MESSAGE_THREAD_KEYS = ["threadId", "thread_id", "messageThreadId", "topicId"];
|
||||
|
||||
@@ -1594,11 +1594,12 @@ describe("runCodexAppServerAttempt", () => {
|
||||
expect(dynamicToolNames).toEqual(["message"]);
|
||||
});
|
||||
|
||||
it("keeps searchable OpenClaw dynamic tools when code-mode-only is enabled", () => {
|
||||
it("keeps OpenClaw control-path tools direct when code-mode-only is enabled", () => {
|
||||
const tools = [
|
||||
createRuntimeDynamicTool("message"),
|
||||
createRuntimeDynamicTool("web_search"),
|
||||
createRuntimeDynamicTool("heartbeat_respond"),
|
||||
createRuntimeDynamicTool("agents_list"),
|
||||
createRuntimeDynamicTool("sessions_spawn"),
|
||||
createRuntimeDynamicTool("sessions_yield"),
|
||||
];
|
||||
@@ -1612,6 +1613,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
const message = specs.find((tool) => tool.name === "message");
|
||||
const webSearch = specs.find((tool) => tool.name === "web_search");
|
||||
const heartbeat = specs.find((tool) => tool.name === "heartbeat_respond");
|
||||
const agentsList = specs.find((tool) => tool.name === "agents_list");
|
||||
const sessionsSpawn = specs.find((tool) => tool.name === "sessions_spawn");
|
||||
const sessionsYield = specs.find((tool) => tool.name === "sessions_yield");
|
||||
|
||||
@@ -1621,13 +1623,15 @@ describe("runCodexAppServerAttempt", () => {
|
||||
expect(webSearch?.deferLoading).toBe(true);
|
||||
expect(heartbeat?.namespace).toBe(CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE);
|
||||
expect(heartbeat?.deferLoading).toBe(true);
|
||||
expect(sessionsSpawn?.namespace).toBe(CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE);
|
||||
expect(sessionsSpawn?.deferLoading).toBe(true);
|
||||
expect(agentsList).not.toHaveProperty("namespace");
|
||||
expect(agentsList).not.toHaveProperty("deferLoading");
|
||||
expect(sessionsSpawn).not.toHaveProperty("namespace");
|
||||
expect(sessionsSpawn).not.toHaveProperty("deferLoading");
|
||||
expect(sessionsYield).not.toHaveProperty("namespace");
|
||||
expect(sessionsYield).not.toHaveProperty("deferLoading");
|
||||
});
|
||||
|
||||
it("registers heartbeat response durably without advertising it on normal turns", async () => {
|
||||
it("keeps the heartbeat schema deferred and stable across normal and heartbeat turns", async () => {
|
||||
testing.setOpenClawCodingToolsFactoryForTests((options) => [
|
||||
createRuntimeDynamicTool("message"),
|
||||
...(options?.enableHeartbeatTool === true
|
||||
@@ -1640,12 +1644,10 @@ describe("runCodexAppServerAttempt", () => {
|
||||
const params = createParams(sessionFile, workspaceDir);
|
||||
params.disableTools = false;
|
||||
params.runtimePlan = createCodexRuntimePlanFixture();
|
||||
params.sourceReplyDeliveryMode = "message_tool_only";
|
||||
if (trigger) {
|
||||
params.trigger = trigger;
|
||||
}
|
||||
if (trigger === "heartbeat") {
|
||||
params.sourceReplyDeliveryMode = "message_tool_only";
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
@@ -1661,30 +1663,76 @@ describe("runCodexAppServerAttempt", () => {
|
||||
const normalInstructions = testing.buildDeveloperInstructions(createRunParams(), {
|
||||
dynamicTools: normalBridge.availableSpecs,
|
||||
});
|
||||
const heartbeatParams = createRunParams("heartbeat");
|
||||
const heartbeatBridge = createCodexToolBridgeForTest(
|
||||
heartbeatParams,
|
||||
[createRuntimeDynamicTool("message"), createRuntimeDynamicTool("heartbeat_respond")],
|
||||
registeredTools,
|
||||
);
|
||||
const heartbeatInstructions = testing.buildDeveloperInstructions(heartbeatParams, {
|
||||
dynamicTools: heartbeatBridge.availableSpecs,
|
||||
});
|
||||
const nextNormalParams = createRunParams();
|
||||
const nextNormalBridge = createCodexToolBridgeForTest(
|
||||
nextNormalParams,
|
||||
[createRuntimeDynamicTool("message")],
|
||||
registeredTools,
|
||||
);
|
||||
const registeredToolNames = specNames(normalBridge.specs);
|
||||
|
||||
expect(registeredToolNames).toContain("message");
|
||||
expect(registeredToolNames).toContain("heartbeat_respond");
|
||||
expect(normalInstructions).toContain(
|
||||
"Deferred searchable OpenClaw dynamic tools available: message.",
|
||||
);
|
||||
expect(normalInstructions).not.toContain(
|
||||
"Deferred searchable OpenClaw dynamic tools available: heartbeat_respond",
|
||||
);
|
||||
|
||||
const heartbeatBridge = createCodexToolBridgeForTest(
|
||||
createRunParams("heartbeat"),
|
||||
[createRuntimeDynamicTool("message"), createRuntimeDynamicTool("heartbeat_respond")],
|
||||
registeredTools,
|
||||
expect(heartbeatInstructions).toContain(
|
||||
"Deferred searchable OpenClaw dynamic tools available: heartbeat_respond.",
|
||||
);
|
||||
const nextNormalBridge = createCodexToolBridgeForTest(
|
||||
createRunParams(),
|
||||
[createRuntimeDynamicTool("message")],
|
||||
registeredTools,
|
||||
for (const bridge of [normalBridge, heartbeatBridge, nextNormalBridge]) {
|
||||
const heartbeat = flattenSpecsWithNamespace(bridge.specs).find(
|
||||
(tool) => tool.name === "heartbeat_respond",
|
||||
);
|
||||
expect(heartbeat?.namespace).toBe(CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE);
|
||||
expect(heartbeat?.deferLoading).toBe(true);
|
||||
}
|
||||
expect(codexDynamicToolsFingerprint(heartbeatBridge.specs)).toBe(
|
||||
codexDynamicToolsFingerprint(normalBridge.specs),
|
||||
);
|
||||
expect(codexDynamicToolsFingerprint(nextNormalBridge.specs)).toBe(
|
||||
codexDynamicToolsFingerprint(normalBridge.specs),
|
||||
);
|
||||
|
||||
expect(specNames(heartbeatBridge.specs)).toEqual(registeredToolNames);
|
||||
expect(specNames(nextNormalBridge.specs)).toEqual(registeredToolNames);
|
||||
let startedThreadId: string | undefined;
|
||||
const request = vi.fn(async (method: string) => {
|
||||
if (method === "thread/start") {
|
||||
startedThreadId = "thread-stable-heartbeat";
|
||||
return threadStartResult(startedThreadId);
|
||||
}
|
||||
if (method === "thread/resume") {
|
||||
return threadStartResult(startedThreadId);
|
||||
}
|
||||
throw new Error(`unexpected method: ${method}`);
|
||||
});
|
||||
const turns = [
|
||||
{ params: createRunParams(), bridge: normalBridge },
|
||||
{ params: heartbeatParams, bridge: heartbeatBridge },
|
||||
{ params: nextNormalParams, bridge: nextNormalBridge },
|
||||
];
|
||||
for (const turn of turns) {
|
||||
await startOrResumeThread({
|
||||
client: { request } as never,
|
||||
params: turn.params,
|
||||
cwd: workspaceDir,
|
||||
dynamicTools: turn.bridge.specs,
|
||||
appServer: createThreadLifecycleAppServerOptions(),
|
||||
});
|
||||
}
|
||||
|
||||
expect(request.mock.calls.map(([method]) => method)).toEqual([
|
||||
"thread/start",
|
||||
"thread/resume",
|
||||
"thread/resume",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps message in the registered schema when disabled for an internal turn", async () => {
|
||||
|
||||
+102
-104
@@ -124,6 +124,108 @@
|
||||
"name": "message",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot; `mode=\"session\"` persistent/thread-bound, only when requester channel supports thread bindings. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work; run-mode results return, session-mode output stays in thread.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run", "session"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"description": "Bind spawn to new chat thread when supported. `thread=true` defaults mode=\"session\".",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "End current turn. Use after spawning subagents; results arrive as next message.",
|
||||
"inputSchema": {
|
||||
@@ -1001,16 +1103,6 @@
|
||||
"name": "gateway",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List visible sessions; filter by kind, label, agentId, search, activity. Use before sessions_history or sessions_send target selection.",
|
||||
@@ -1117,100 +1209,6 @@
|
||||
"name": "sessions_send",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot; `mode=\"session\"` persistent/thread-bound, only when requester channel supports thread bindings. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work; run-mode results return, session-mode output stays in thread.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run", "session"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"description": "Bind spawn to new chat thread when supported. `thread=true` defaults mode=\"session\".",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List active and recent subagents for the requester session. If sessions_yield exists, use it for completion; do not poll wait loops.",
|
||||
|
||||
+98
-100
@@ -124,6 +124,104 @@
|
||||
"name": "message",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background work. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work while run-mode results return.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "End current turn. Use after spawning subagents; results arrive as next message.",
|
||||
"inputSchema": {
|
||||
@@ -1037,16 +1135,6 @@
|
||||
"name": "gateway",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List visible sessions; filter by kind, label, agentId, search, activity. Use before sessions_history or sessions_send target selection.",
|
||||
@@ -1153,96 +1241,6 @@
|
||||
"name": "sessions_send",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background work. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work while run-mode results return.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List active and recent subagents for the requester session. If sessions_yield exists, use it for completion; do not poll wait loops.",
|
||||
|
||||
+98
-100
@@ -124,6 +124,104 @@
|
||||
"name": "message",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background work. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work while run-mode results return.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"description": "End current turn. Use after spawning subagents; results arrive as next message.",
|
||||
"inputSchema": {
|
||||
@@ -1001,16 +1099,6 @@
|
||||
"name": "gateway",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List agent ids allowed for `sessions_spawn runtime=\"subagent\"`.",
|
||||
"inputSchema": {
|
||||
"properties": {},
|
||||
"type": "object"
|
||||
},
|
||||
"name": "agents_list",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List visible sessions; filter by kind, label, agentId, search, activity. Use before sessions_history or sessions_send target selection.",
|
||||
@@ -1117,96 +1205,6 @@
|
||||
"name": "sessions_send",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background work. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work. Delegate sidecar/parallel tasks: batch file reads, multi-step searches, data collection. Avoid delegating quick lookups or single-file reads unless policy prefers delegation. After spawning, do non-overlapping work while run-mode results return.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"agentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attachAs": {
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"enum": ["utf8", "base64"],
|
||||
"type": "string"
|
||||
},
|
||||
"mimeType": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "content"],
|
||||
"type": "object"
|
||||
},
|
||||
"maxItems": 50,
|
||||
"type": "array"
|
||||
},
|
||||
"cleanup": {
|
||||
"enum": ["delete", "keep"],
|
||||
"type": "string"
|
||||
},
|
||||
"context": {
|
||||
"description": "Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript.",
|
||||
"enum": ["isolated", "fork"],
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"lightContext": {
|
||||
"description": "Light bootstrap context; runtime=\"subagent\" only.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["run"],
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime": {
|
||||
"enum": ["subagent"],
|
||||
"type": "string"
|
||||
},
|
||||
"sandbox": {
|
||||
"enum": ["inherit", "require"],
|
||||
"type": "string"
|
||||
},
|
||||
"task": {
|
||||
"type": "string"
|
||||
},
|
||||
"taskName": {
|
||||
"description": "Stable alias for later targeting; lowercase letters/digits/underscores/hyphens, starts letter.",
|
||||
"type": "string"
|
||||
},
|
||||
"thinking": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["task"],
|
||||
"type": "object"
|
||||
},
|
||||
"name": "sessions_spawn",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"deferLoading": true,
|
||||
"description": "List active and recent subagents for the requester session. If sessions_yield exists, use it for completion; do not poll wait loops.",
|
||||
|
||||
Vendored
+13
-13
@@ -88,16 +88,16 @@
|
||||
"developerInstructions": "<see Reconstructed Model-Bound Prompt Layers>",
|
||||
"dynamicTools": [
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
@@ -227,20 +227,20 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 50951,
|
||||
"roughTokens": 12738
|
||||
"chars": 50395,
|
||||
"roughTokens": 12599
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 3074,
|
||||
"roughTokens": 769
|
||||
"chars": 3045,
|
||||
"roughTokens": 762
|
||||
},
|
||||
"totalTextOnly": {
|
||||
"chars": 27692,
|
||||
"roughTokens": 6923
|
||||
"chars": 27663,
|
||||
"roughTokens": 6916
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 78645,
|
||||
"roughTokens": 19662
|
||||
"chars": 78060,
|
||||
"roughTokens": 19515
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1535,
|
||||
@@ -427,7 +427,7 @@ Approval policy is currently never. Do not provide the `sandbox_permissions` for
|
||||
````text
|
||||
You are a personal agent running inside OpenClaw. OpenClaw has dynamic tools for OpenClaw-owned messaging, cron, sessions, media, gateway, and nodes.
|
||||
|
||||
Deferred searchable OpenClaw dynamic tools available: agents_list, cron, gateway, nodes, session_status, sessions_history, sessions_list, sessions_send, sessions_spawn, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
Deferred searchable OpenClaw dynamic tools available: cron, gateway, nodes, session_status, sessions_history, sessions_list, sessions_send, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
|
||||
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
|
||||
|
||||
@@ -560,16 +560,16 @@ Full JSON: `codex-dynamic-tools.discord-group.json`
|
||||
```json
|
||||
[
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
|
||||
test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-direct-codex-message-tool.md
Vendored
+13
-13
@@ -88,16 +88,16 @@
|
||||
"developerInstructions": "<see Reconstructed Model-Bound Prompt Layers>",
|
||||
"dynamicTools": [
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
@@ -227,20 +227,20 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 50620,
|
||||
"roughTokens": 12655
|
||||
"chars": 50084,
|
||||
"roughTokens": 12521
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 1965,
|
||||
"roughTokens": 492
|
||||
"chars": 1936,
|
||||
"roughTokens": 484
|
||||
},
|
||||
"totalTextOnly": {
|
||||
"chars": 26081,
|
||||
"roughTokens": 6521
|
||||
"chars": 26052,
|
||||
"roughTokens": 6513
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 76703,
|
||||
"roughTokens": 19176
|
||||
"chars": 76138,
|
||||
"roughTokens": 19035
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1033,
|
||||
@@ -427,7 +427,7 @@ Approval policy is currently never. Do not provide the `sandbox_permissions` for
|
||||
````text
|
||||
You are a personal agent running inside OpenClaw. OpenClaw has dynamic tools for OpenClaw-owned messaging, cron, sessions, media, gateway, and nodes.
|
||||
|
||||
Deferred searchable OpenClaw dynamic tools available: agents_list, cron, gateway, nodes, session_status, sessions_history, sessions_list, sessions_send, sessions_spawn, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
Deferred searchable OpenClaw dynamic tools available: cron, gateway, nodes, session_status, sessions_history, sessions_list, sessions_send, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
|
||||
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
|
||||
|
||||
@@ -537,16 +537,16 @@ Full JSON: `codex-dynamic-tools.telegram-direct.json`
|
||||
```json
|
||||
[
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
|
||||
Vendored
+13
-13
@@ -88,17 +88,17 @@
|
||||
"developerInstructions": "<see Reconstructed Model-Bound Prompt Layers>",
|
||||
"dynamicTools": [
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"heartbeat_respond",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
@@ -228,20 +228,20 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
|
||||
"roughTokens": 0
|
||||
},
|
||||
"dynamicToolsJson": {
|
||||
"chars": 51910,
|
||||
"roughTokens": 12978
|
||||
"chars": 51374,
|
||||
"roughTokens": 12844
|
||||
},
|
||||
"openClawDeveloperInstructions": {
|
||||
"chars": 1984,
|
||||
"roughTokens": 496
|
||||
"chars": 1955,
|
||||
"roughTokens": 489
|
||||
},
|
||||
"totalTextOnly": {
|
||||
"chars": 27024,
|
||||
"roughTokens": 6756
|
||||
"chars": 26995,
|
||||
"roughTokens": 6749
|
||||
},
|
||||
"totalWithDynamicToolsJson": {
|
||||
"chars": 78936,
|
||||
"roughTokens": 19734
|
||||
"chars": 78371,
|
||||
"roughTokens": 19593
|
||||
},
|
||||
"userInputText": {
|
||||
"chars": 1271,
|
||||
@@ -428,7 +428,7 @@ Approval policy is currently never. Do not provide the `sandbox_permissions` for
|
||||
````text
|
||||
You are a personal agent running inside OpenClaw. OpenClaw has dynamic tools for OpenClaw-owned messaging, cron, sessions, media, gateway, and nodes.
|
||||
|
||||
Deferred searchable OpenClaw dynamic tools available: agents_list, cron, gateway, heartbeat_respond, nodes, session_status, sessions_history, sessions_list, sessions_send, sessions_spawn, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
Deferred searchable OpenClaw dynamic tools available: cron, gateway, heartbeat_respond, nodes, session_status, sessions_history, sessions_list, sessions_send, subagents, tts, web_fetch, web_search. Use `tool_search` to load exact callable specs before use.
|
||||
|
||||
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
|
||||
|
||||
@@ -547,17 +547,17 @@ Full JSON: `codex-dynamic-tools.heartbeat-turn.json`
|
||||
```json
|
||||
[
|
||||
"message",
|
||||
"agents_list",
|
||||
"sessions_spawn",
|
||||
"sessions_yield",
|
||||
"nodes",
|
||||
"cron",
|
||||
"heartbeat_respond",
|
||||
"tts",
|
||||
"gateway",
|
||||
"agents_list",
|
||||
"sessions_list",
|
||||
"sessions_history",
|
||||
"sessions_send",
|
||||
"sessions_spawn",
|
||||
"subagents",
|
||||
"session_status",
|
||||
"web_search",
|
||||
|
||||
Reference in New Issue
Block a user