mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:40:42 +00:00
fix: steer agents to safe gateway config flow
This commit is contained in:
@@ -88,6 +88,7 @@ Docs: https://docs.openclaw.ai
|
||||
plain prompts instead of OpenClaw internal runtime-context envelopes, while
|
||||
keeping those envelopes out of ACP transcripts.
|
||||
- TTS/status: show configured TTS model, voice, and sanitized custom endpoint in `/status`, preserve OpenAI-compatible TTS instructions on custom endpoints, and retry empty Microsoft/Edge TTS output once. Addresses #46602, #47232, and #43936. Thanks @leekuangtao, @Huntterxx, and @rex993.
|
||||
- Agents/Gateway: steer agent-driven config edits and restarts through the owner-only `gateway` tool, document `config.schema.lookup` as the field-doc source, and warn against using `gateway stop && gateway start` as a restart substitute on macOS. Fixes #71929. Thanks @ygc3817922006-sketch.
|
||||
- Providers/vLLM: send Nemotron 3 chat-template kwargs when thinking is off
|
||||
and honor configured `params.chat_template_kwargs` for OpenAI-compatible
|
||||
completions, so vLLM/Nemotron replies stay visible instead of becoming
|
||||
|
||||
@@ -324,6 +324,7 @@ Command options:
|
||||
Notes:
|
||||
|
||||
- `gateway install` supports `--port`, `--runtime`, `--token`, `--force`, `--json`.
|
||||
- Use `gateway restart` to restart a managed service. Do not chain `gateway stop` and `gateway start` as a restart substitute; on macOS, `gateway stop` intentionally disables the LaunchAgent before stopping it.
|
||||
- When token auth requires a token and `gateway.auth.token` is SecretRef-managed, `gateway install` validates that the SecretRef is resolvable but does not persist the resolved token into service environment metadata.
|
||||
- If token auth requires a token and the configured token SecretRef is unresolved, install fails closed instead of persisting fallback plaintext.
|
||||
- For password auth on `gateway run`, prefer `OPENCLAW_GATEWAY_PASSWORD`, `--password-file`, or a SecretRef-backed `gateway.auth.password` over inline `--password`.
|
||||
|
||||
@@ -214,6 +214,10 @@ stale. The prompt also notes the public docs mirror, community Discord, and Claw
|
||||
([https://clawhub.ai](https://clawhub.ai)) for skills discovery. It tells the model to
|
||||
consult docs first for OpenClaw behavior, commands, configuration, or architecture, and to
|
||||
run `openclaw status` itself when possible (asking the user only when it lacks access).
|
||||
For configuration specifically, it points agents to the `gateway` tool action
|
||||
`config.schema.lookup` for exact field-level docs and constraints, then to
|
||||
`docs/gateway/configuration.md` and `docs/gateway/configuration-reference.md`
|
||||
for broader guidance.
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ Code truth:
|
||||
- `config.schema.lookup` returns one path-scoped schema node for drill-down tooling
|
||||
- `pnpm config:docs:check` / `pnpm config:docs:gen` validate the config-doc baseline hash against the current schema surface
|
||||
|
||||
Agent lookup path: use the `gateway` tool action `config.schema.lookup` for
|
||||
exact field-level docs and constraints before edits. Use
|
||||
[Configuration](/gateway/configuration) for task-oriented guidance and this page
|
||||
for the broader field map, defaults, and links to subsystem references.
|
||||
|
||||
Dedicated deep references:
|
||||
|
||||
- [Memory configuration reference](/reference/memory-config) for `agents.defaults.memorySearch.*`, `memory.qmd.*`, `memory.citations`, and dreaming config under `plugins.entries.memory-core.config.dreaming`
|
||||
|
||||
@@ -21,6 +21,11 @@ If the file is missing, OpenClaw uses safe defaults. Common reasons to add a con
|
||||
|
||||
See the [full reference](/gateway/configuration-reference) for every available field.
|
||||
|
||||
Agents and automation should use `config.schema.lookup` for exact field-level
|
||||
docs before editing config. Use this page for task-oriented guidance and
|
||||
[Configuration reference](/gateway/configuration-reference) for the broader
|
||||
field map and defaults.
|
||||
|
||||
<Tip>
|
||||
**New to configuration?** Start with `openclaw onboard` for interactive setup, or check out the [Configuration Examples](/gateway/configuration-examples) guide for complete copy-paste configs.
|
||||
</Tip>
|
||||
@@ -575,6 +580,11 @@ For tooling that writes config over the gateway API, prefer this flow:
|
||||
- `config.apply` only when you intend to replace the entire config
|
||||
- `update.run` for explicit self-update plus restart
|
||||
|
||||
Agents should treat `config.schema.lookup` as the first stop for exact
|
||||
field-level docs and constraints. Use [Configuration reference](/gateway/configuration-reference)
|
||||
when they need the broader config map, defaults, or links to dedicated
|
||||
subsystem references.
|
||||
|
||||
<Note>
|
||||
Control-plane writes (`config.apply`, `config.patch`, `update.run`) are
|
||||
rate-limited to 3 requests per 60 seconds per `deviceId+clientIp`. Restart
|
||||
|
||||
@@ -251,6 +251,8 @@ openclaw gateway restart
|
||||
openclaw gateway stop
|
||||
```
|
||||
|
||||
Use `openclaw gateway restart` for restarts. Do not chain `openclaw gateway stop` and `openclaw gateway start`; on macOS, `gateway stop` intentionally disables the LaunchAgent before stopping it.
|
||||
|
||||
LaunchAgent labels are `ai.openclaw.gateway` (default) or `ai.openclaw.<profile>` (named profile). `openclaw doctor` audits and repairs service config drift.
|
||||
|
||||
</Tab>
|
||||
|
||||
@@ -95,6 +95,8 @@ active runtime model label from the latest transcript usage entry.
|
||||
|
||||
For partial changes, prefer `config.schema.lookup` then `config.patch`. Use
|
||||
`config.apply` only when you intentionally replace the entire config.
|
||||
For broader config docs, read [Configuration](/gateway/configuration) and
|
||||
[Configuration reference](/gateway/configuration-reference).
|
||||
The tool also refuses to change `tools.exec.ask` or `tools.exec.security`;
|
||||
legacy `tools.bash.*` aliases normalize to the same protected exec paths.
|
||||
|
||||
|
||||
@@ -25,6 +25,29 @@ function requireGatewayTool(agentSessionKey?: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function collectActionValues(schema: unknown, values: Set<string>): void {
|
||||
if (!schema || typeof schema !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const record = schema as Record<string, unknown>;
|
||||
if (typeof record.const === "string") {
|
||||
values.add(record.const);
|
||||
}
|
||||
if (Array.isArray(record.enum)) {
|
||||
for (const value of record.enum) {
|
||||
if (typeof value === "string") {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Array.isArray(record.anyOf)) {
|
||||
for (const variant of record.anyOf) {
|
||||
collectActionValues(variant, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function expectConfigMutationCall(params: {
|
||||
callGatewayTool: {
|
||||
mock: {
|
||||
@@ -96,6 +119,19 @@ describe("gateway tool", () => {
|
||||
expect(tool.ownerOnly).toBe(true);
|
||||
});
|
||||
|
||||
it("exposes restart and config actions in the gateway tool schema", async () => {
|
||||
const tool = requireGatewayTool();
|
||||
const parameters = tool.parameters as {
|
||||
properties?: Record<string, unknown>;
|
||||
};
|
||||
const values = new Set<string>();
|
||||
collectActionValues(parameters.properties?.action, values);
|
||||
|
||||
expect([...values]).toEqual(
|
||||
expect.arrayContaining(["restart", "config.get", "config.patch", "config.apply"]),
|
||||
);
|
||||
});
|
||||
|
||||
it("schedules SIGUSR1 restart", async () => {
|
||||
const kill = vi.spyOn(process, "kill").mockImplementation(() => true);
|
||||
const restartSignalKillCalls = () =>
|
||||
|
||||
@@ -86,6 +86,25 @@ function expectNoSubagentControlTools(tools: ReturnType<typeof createOpenClawCod
|
||||
describe("createOpenClawCodingTools", () => {
|
||||
const testConfig: OpenClawConfig = {};
|
||||
|
||||
it("exposes gateway config and restart actions to owner sessions", () => {
|
||||
const tools = createOpenClawCodingTools({ config: testConfig, senderIsOwner: true });
|
||||
const gateway = tools.find((tool) => tool.name === "gateway");
|
||||
expect(gateway).toBeDefined();
|
||||
|
||||
const parameters = gateway?.parameters as {
|
||||
properties?: Record<string, unknown>;
|
||||
};
|
||||
const action = parameters.properties?.action as
|
||||
| { const?: unknown; enum?: unknown[] }
|
||||
| undefined;
|
||||
const values = new Set<string>();
|
||||
collectActionValues(action, values);
|
||||
|
||||
expect([...values]).toEqual(
|
||||
expect.arrayContaining(["restart", "config.get", "config.patch", "config.apply"]),
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves action enums in normalized schemas", () => {
|
||||
const defaultTools = createOpenClawCodingTools({ config: testConfig, senderIsOwner: true });
|
||||
const toolNames = ["canvas", "nodes", "cron", "gateway", "message"];
|
||||
|
||||
@@ -226,10 +226,27 @@ describe("buildAgentSystemPrompt", () => {
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## OpenClaw CLI Quick Reference");
|
||||
expect(prompt).toContain("use the first-class `gateway` tool");
|
||||
expect(prompt).toContain(
|
||||
"Only use CLI service lifecycle commands when the user explicitly asks",
|
||||
);
|
||||
expect(prompt).toContain("openclaw gateway restart");
|
||||
expect(prompt).toContain("Do not chain `openclaw gateway stop`");
|
||||
expect(prompt).toContain("Do not invent commands");
|
||||
});
|
||||
|
||||
it("points agents to config field docs and broader configuration docs", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
docsPath: "/tmp/openclaw/docs",
|
||||
});
|
||||
|
||||
expect(prompt).toContain("For config field docs");
|
||||
expect(prompt).toContain("`gateway` tool action `config.schema.lookup`");
|
||||
expect(prompt).toContain("docs/gateway/configuration.md");
|
||||
expect(prompt).toContain("docs/gateway/configuration-reference.md");
|
||||
});
|
||||
|
||||
it("guides runtime completion events without exposing internal metadata", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
@@ -559,6 +576,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
expect(prompt).toContain("config.schema.lookup");
|
||||
expect(prompt).toContain("config.apply");
|
||||
expect(prompt).toContain("config.patch");
|
||||
expect(prompt).toContain("Config writes hot-reload when possible");
|
||||
expect(prompt).toContain("update.run");
|
||||
expect(prompt).not.toContain("Use config.schema to");
|
||||
expect(prompt).not.toContain("config.schema, config.apply");
|
||||
|
||||
@@ -422,6 +422,7 @@ function buildDocsSection(params: {
|
||||
docsPath
|
||||
? "For OpenClaw behavior, commands, config, or architecture: consult local docs first."
|
||||
: "For OpenClaw behavior, commands, config, or architecture: consult the docs mirror first.",
|
||||
"For config field docs, prefer the `gateway` tool action `config.schema.lookup`; for broader config guidance, read `docs/gateway/configuration.md` and `docs/gateway/configuration-reference.md`.",
|
||||
sourcePath
|
||||
? "If docs are incomplete or stale, inspect the local OpenClaw source code before answering."
|
||||
: "If docs are incomplete or stale, review the OpenClaw source on GitHub before answering.",
|
||||
@@ -784,11 +785,15 @@ export function buildAgentSystemPrompt(params: {
|
||||
...safetySection,
|
||||
"## OpenClaw CLI Quick Reference",
|
||||
"OpenClaw is controlled via subcommands. Do not invent commands.",
|
||||
"To manage the Gateway daemon service (start/stop/restart):",
|
||||
"For config changes, use the first-class `gateway` tool (`config.schema.lookup`, `config.get`, `config.patch`, `config.apply`) instead of editing config through exec; the gateway tool hot-reloads config when possible and uses a safe restart only when required.",
|
||||
"Use the `gateway` tool action `restart` for Gateway restarts. Only use CLI service lifecycle commands when the user explicitly asks for them.",
|
||||
"Gateway service lifecycle quick reference:",
|
||||
"- openclaw gateway status",
|
||||
"- openclaw gateway restart",
|
||||
"Operator-only, explicit user request:",
|
||||
"- openclaw gateway start",
|
||||
"- openclaw gateway stop",
|
||||
"- openclaw gateway restart",
|
||||
"Do not chain `openclaw gateway stop` and `openclaw gateway start` as a restart substitute.",
|
||||
"If unsure, ask the user to run `openclaw help` (or `openclaw gateway --help`) and paste the output.",
|
||||
"",
|
||||
...skillsSection,
|
||||
@@ -800,7 +805,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
|
||||
"Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
|
||||
"Use config.schema.lookup with a specific dot path to inspect only the relevant config subtree before making config changes or answering config-field questions; avoid guessing field names/types.",
|
||||
"Actions: config.schema.lookup, config.get, config.apply (validate + write full config, then restart), config.patch (partial update, merges with existing), update.run (update deps or git, then restart).",
|
||||
"Actions: config.schema.lookup, config.get, config.patch (partial update, merges with existing), config.apply (validate + write full config), update.run (update deps or git, then restart). Config writes hot-reload when possible and use a safe restart only when required.",
|
||||
"After restart, OpenClaw pings the last active session automatically.",
|
||||
].join("\n")
|
||||
: "",
|
||||
|
||||
@@ -22,7 +22,14 @@ const coreTools = [
|
||||
stubActionTool("nodes", ["list", "invoke"]),
|
||||
stubActionTool("cron", ["schedule", "cancel"]),
|
||||
stubActionTool("message", ["send", "reply"]),
|
||||
stubActionTool("gateway", ["status"]),
|
||||
stubActionTool("gateway", [
|
||||
"restart",
|
||||
"config.get",
|
||||
"config.schema.lookup",
|
||||
"config.apply",
|
||||
"config.patch",
|
||||
"update.run",
|
||||
]),
|
||||
stubActionTool("agents_list", ["list", "show"]),
|
||||
stubActionTool("sessions_list", ["list", "show"]),
|
||||
stubActionTool("sessions_history", ["read", "tail"]),
|
||||
|
||||
Reference in New Issue
Block a user