fix(agents): follow through on promised asynchronous work (#105958)

* fix(agents): close promised asynchronous work loops

* fix(agents): close promised asynchronous work loops

* refactor(agents): keep promised work policy focused

* refactor(agents): preserve prompt module documentation

* style(agents): keep prompt renderer within LOC ratchet

* fix(agents): close promised asynchronous work loops

* fix(agents): close promised asynchronous work loops
This commit is contained in:
Jason (Json)
2026-07-13 00:56:04 -06:00
committed by GitHub
parent f1076c23d4
commit 4e1224ddbe
6 changed files with 60 additions and 0 deletions

View File

@@ -223,6 +223,7 @@ describe("buildEmbeddedSystemPrompt", () => {
nativeCommandGuidanceLines: ["Subagent-only command guidance."],
modelAliasLines: [],
userTimezone: "UTC",
promptMode: "minimal",
});
expect(prompt).toContain("- sessions_spawn");
@@ -231,6 +232,9 @@ describe("buildEmbeddedSystemPrompt", () => {
expect(prompt).not.toContain("Larger work: use `sessions_spawn`");
expect(prompt).not.toContain("Do not poll `subagents list` / `sessions_list` in a loop");
expect(prompt).toContain("Subagent-only command guidance.");
expect(prompt).toContain("## Promised Work");
expect(prompt).toContain("Progress such as `running` is not completion.");
expect(prompt.match(/## Promised Work/g)).toHaveLength(1);
});
it("can omit base memory guidance for non-legacy context engines", () => {

View File

@@ -0,0 +1,12 @@
/** Shared prompt policy for commitments that outlive the current turn. */
export function buildPromisedWorkPromptSection(): string[] {
return [
"## Promised Work",
"- Promising future, background, delegated, or continued work creates follow-through ownership.",
"- Before ending a turn, arrange an available push-based completion or watch path; keep the originating request and any existing goal or task open.",
"- Proactively return with the result, link, proof, or a concrete blocker; do not wait for the requester to ask.",
"- If no completion path exists, do not promise later; stay in the turn or state the blocker.",
"- Progress such as `running` is not completion.",
"",
];
}

View File

@@ -0,0 +1,19 @@
import { describe, expect, it } from "vitest";
import { buildSystemPrompt } from "./system-prompt.js";
describe("buildSystemPrompt", () => {
it("includes promised-work policy in the default prompt only", () => {
const prompt = buildSystemPrompt({ cwd: "/tmp/workspace" });
expect(prompt).toContain("## Promised Work");
expect(prompt).toContain("Progress such as `running` is not completion.");
expect(prompt.match(/## Promised Work/g)).toHaveLength(1);
expect(
buildSystemPrompt({
cwd: "/tmp/workspace",
customPrompt: "Custom replacement prompt",
}),
).not.toContain("## Promised Work");
});
});

View File

@@ -4,6 +4,7 @@
import { formatSkillsForPrompt, type Skill } from "../../skills/loading/session.js";
import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
import { buildPromisedWorkPromptSection } from "../promised-work-prompt.js";
export interface BuildSystemPromptOptions {
/** Custom system prompt (replaces default). */
@@ -143,6 +144,8 @@ In addition to the tools above, you may have access to other custom tools depend
Guidelines:
${guidelines}
${buildPromisedWorkPromptSection().join("\n")}
Embedded agent documentation (read only when the user asks about the embedded agent SDK, extensions, themes, skills, or TUI):
- Main documentation: ${readmePath}
- Additional docs: ${docsPath}

View File

@@ -164,6 +164,26 @@ describe("buildAgentSystemPrompt", () => {
expect(prompt).toContain("Subagent details");
});
it("keeps promised asynchronous work open in full and minimal prompts", () => {
for (const promptMode of ["full", "minimal"] as const) {
const prompt = buildAgentSystemPrompt({
workspaceDir: "/tmp/openclaw",
promptMode,
});
expect(prompt).toContain("## Promised Work");
expect(prompt).toContain("Progress such as `running` is not completion.");
expect(prompt.match(/## Promised Work/g)).toHaveLength(1);
}
expect(
buildAgentSystemPrompt({
workspaceDir: "/tmp/openclaw",
promptMode: "none",
}),
).not.toContain("## Promised Work");
});
it("can omit generic silent-reply guidance for channel-aware prompts", () => {
const prompt = buildAgentSystemPrompt({
workspaceDir: "/tmp/openclaw",

View File

@@ -44,6 +44,7 @@ import type {
EmbeddedFullAccessBlockedReason,
EmbeddedSandboxInfo,
} from "./embedded-agent-runner/types.js";
import { buildPromisedWorkPromptSection } from "./promised-work-prompt.js";
import {
buildOpenClawToolFallbackText,
shouldRenderOpenClawToolWorkflowHints,
@@ -1142,6 +1143,7 @@ export function buildAgentSystemPrompt(params: {
isMinimal,
}),
}),
...buildPromisedWorkPromptSection(),
...buildOverridablePromptSection({
override: providerStablePrefix,
fallback: [],