Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions nemoclaw/src/runtime-context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ describe("getRuntimeSummary", () => {
expect(summary.sandboxName).toBe("openclaw");
expect(summary.sandboxPhase).toBeNull();
expect(summary.networkLines).toContain(
"outbound network is deny-by-default; assume no arbitrary internet access",
"outbound network is deny-by-default, but allowed endpoints work, so verify by attempting a request rather than assuming a host is unreachable",
);
expect(summary.filesystemLines).toContain(
"filesystem/process access is sandboxed; do not assume host-level access",
"filesystem and process access are scoped to the sandbox, not the host; do not assume access to host paths outside it",
);
});

Expand Down Expand Up @@ -137,6 +137,13 @@ describe("registerRuntimeContext", () => {
expect(result.prependSystemContext).toContain("Network policy:");
expect(result.prependSystemContext).toContain("Filesystem policy:");
expect(result.prependSystemContext).toContain("</nemoclaw-runtime>");
// Grounding directive: the agent must attempt before asserting a host is
// blocked rather than refusing preemptively, and report the real failure
// mode instead of assuming a specific status code.
expect(result.prependSystemContext).toContain(
"unless you have actually attempted it this turn",
);
expect(result.prependSystemContext).toContain("raises an operator approval request");
});

it("uses the persisted sandbox name in the injected context", async () => {
Expand Down
12 changes: 7 additions & 5 deletions nemoclaw/src/runtime-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ interface RuntimeSummary {
}

const STATIC_NETWORK_LINES = [
"outbound network is deny-by-default; assume no arbitrary internet access",
"blocked requests can return proxy 403 and may need operator approval or policy changes",
"outbound network is deny-by-default, but allowed endpoints work, so verify by attempting a request rather than assuming a host is unreachable",
"attempting a restricted endpoint is productive: a proxy or policy denial raises an operator approval request in OpenShell, so make the request rather than refusing preemptively; if it fails, report the actual error and distinguish a policy denial (which the operator can approve) from other network errors such as DNS, timeout, or TLS failures",
];

const STATIC_FILESYSTEM_LINES = [
"filesystem/process access is sandboxed; do not assume host-level access",
"filesystem and process access are scoped to the sandbox, not the host; do not assume access to host paths outside it",
"within the sandbox you can create, edit, and run files (for example in /tmp or /sandbox) using your file and shell tools; try the operation and report if it fails rather than assuming it is unavailable",
];

/**
Expand Down Expand Up @@ -63,8 +64,9 @@ function buildRuntimeContextText(summary: RuntimeSummary): string {
"Filesystem policy:",
...summary.filesystemLines.map((line) => `- ${line}`),
"Behavior:",
"- Do not claim unrestricted host or internet access.",
"- if access is blocked, say it is blocked and ask the operator to adjust policy or approve it in OpenShell",
"- Do not assert that a URL or host is blocked or unreachable unless you have actually attempted it this turn; report the actual result rather than speculating.",
"- Distinguish a proxy/policy denial, which raises an operator approval request in OpenShell, from other failures such as DNS, timeout, or TLS errors; only a policy denial is something the operator can approve.",
"- Do not claim unrestricted host or internet access either. When unsure, attempt the action and rely on the real result instead of speculating about the environment.",
"</nemoclaw-runtime>",
].filter((line): line is string => Boolean(line));
return lines.join("\n");
Expand Down
Loading