refactor: unify system prompt runtime params
This commit is contained in:
@@ -102,6 +102,7 @@ export async function runCliAgent(params: {
|
|||||||
tools: [],
|
tools: [],
|
||||||
contextFiles,
|
contextFiles,
|
||||||
modelDisplay,
|
modelDisplay,
|
||||||
|
agentId: sessionAgentId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { sessionId: cliSessionIdToSend, isNew } = resolveSessionIdToSend({
|
const { sessionId: cliSessionIdToSend, isNew } = resolveSessionIdToSend({
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import type { ThinkLevel } from "../../auto-reply/thinking.js";
|
|||||||
import type { ClawdbotConfig } from "../../config/config.js";
|
import type { ClawdbotConfig } from "../../config/config.js";
|
||||||
import type { CliBackendConfig } from "../../config/types.js";
|
import type { CliBackendConfig } from "../../config/types.js";
|
||||||
import { runExec } from "../../process/exec.js";
|
import { runExec } from "../../process/exec.js";
|
||||||
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js";
|
|
||||||
import type { EmbeddedContextFile } from "../pi-embedded-helpers.js";
|
import type { EmbeddedContextFile } from "../pi-embedded-helpers.js";
|
||||||
|
import { buildSystemPromptParams } from "../system-prompt-params.js";
|
||||||
import { buildAgentSystemPrompt } from "../system-prompt.js";
|
import { buildAgentSystemPrompt } from "../system-prompt.js";
|
||||||
|
|
||||||
const CLI_RUN_QUEUE = new Map<string, Promise<unknown>>();
|
const CLI_RUN_QUEUE = new Map<string, Promise<unknown>>();
|
||||||
@@ -172,10 +172,19 @@ export function buildSystemPrompt(params: {
|
|||||||
tools: AgentTool[];
|
tools: AgentTool[];
|
||||||
contextFiles?: EmbeddedContextFile[];
|
contextFiles?: EmbeddedContextFile[];
|
||||||
modelDisplay: string;
|
modelDisplay: string;
|
||||||
|
agentId?: string;
|
||||||
}) {
|
}) {
|
||||||
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
|
const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
|
||||||
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
|
config: params.config,
|
||||||
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
|
agentId: params.agentId,
|
||||||
|
runtime: {
|
||||||
|
host: "clawdbot",
|
||||||
|
os: `${os.type()} ${os.release()}`,
|
||||||
|
arch: os.arch(),
|
||||||
|
node: process.version,
|
||||||
|
model: params.modelDisplay,
|
||||||
|
},
|
||||||
|
});
|
||||||
return buildAgentSystemPrompt({
|
return buildAgentSystemPrompt({
|
||||||
workspaceDir: params.workspaceDir,
|
workspaceDir: params.workspaceDir,
|
||||||
defaultThinkLevel: params.defaultThinkLevel,
|
defaultThinkLevel: params.defaultThinkLevel,
|
||||||
@@ -184,13 +193,7 @@ export function buildSystemPrompt(params: {
|
|||||||
reasoningTagHint: false,
|
reasoningTagHint: false,
|
||||||
heartbeatPrompt: params.heartbeatPrompt,
|
heartbeatPrompt: params.heartbeatPrompt,
|
||||||
docsPath: params.docsPath,
|
docsPath: params.docsPath,
|
||||||
runtimeInfo: {
|
runtimeInfo,
|
||||||
host: "clawdbot",
|
|
||||||
os: `${os.type()} ${os.release()}`,
|
|
||||||
arch: os.arch(),
|
|
||||||
node: process.version,
|
|
||||||
model: params.modelDisplay,
|
|
||||||
},
|
|
||||||
toolNames: params.tools.map((tool) => tool.name),
|
toolNames: params.tools.map((tool) => tool.name),
|
||||||
modelAliasLines: buildModelAliasLines(params.config),
|
modelAliasLines: buildModelAliasLines(params.config),
|
||||||
userTimezone,
|
userTimezone,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ import { prewarmSessionFile, trackSessionManagerAccess } from "../session-manage
|
|||||||
import { prepareSessionManagerForRun } from "../session-manager-init.js";
|
import { prepareSessionManagerForRun } from "../session-manager-init.js";
|
||||||
import { buildEmbeddedSystemPrompt, createSystemPromptOverride } from "../system-prompt.js";
|
import { buildEmbeddedSystemPrompt, createSystemPromptOverride } from "../system-prompt.js";
|
||||||
import { splitSdkTools } from "../tool-split.js";
|
import { splitSdkTools } from "../tool-split.js";
|
||||||
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../../date-time.js";
|
import { buildSystemPromptParams } from "../../system-prompt-params.js";
|
||||||
import { describeUnknownError, mapThinkingLevel } from "../utils.js";
|
import { describeUnknownError, mapThinkingLevel } from "../utils.js";
|
||||||
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
||||||
import { isTimeoutError } from "../../failover-error.js";
|
import { isTimeoutError } from "../../failover-error.js";
|
||||||
@@ -196,25 +196,25 @@ export async function runEmbeddedAttempt(
|
|||||||
return level ? { level, channel: "Telegram" } : undefined;
|
return level ? { level, channel: "Telegram" } : undefined;
|
||||||
})()
|
})()
|
||||||
: undefined;
|
: undefined;
|
||||||
const runtimeInfo = {
|
|
||||||
host: machineName,
|
|
||||||
os: `${os.type()} ${os.release()}`,
|
|
||||||
arch: os.arch(),
|
|
||||||
node: process.version,
|
|
||||||
model: `${params.provider}/${params.modelId}`,
|
|
||||||
channel: runtimeChannel,
|
|
||||||
capabilities: runtimeCapabilities,
|
|
||||||
};
|
|
||||||
|
|
||||||
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox, params.bashElevated);
|
|
||||||
const reasoningTagHint = isReasoningTagProvider(params.provider);
|
|
||||||
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
|
|
||||||
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
|
|
||||||
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
|
|
||||||
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
|
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
|
||||||
sessionKey: params.sessionKey,
|
sessionKey: params.sessionKey,
|
||||||
config: params.config,
|
config: params.config,
|
||||||
});
|
});
|
||||||
|
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox, params.bashElevated);
|
||||||
|
const reasoningTagHint = isReasoningTagProvider(params.provider);
|
||||||
|
const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
|
||||||
|
config: params.config,
|
||||||
|
agentId: sessionAgentId,
|
||||||
|
runtime: {
|
||||||
|
host: machineName,
|
||||||
|
os: `${os.type()} ${os.release()}`,
|
||||||
|
arch: os.arch(),
|
||||||
|
node: process.version,
|
||||||
|
model: `${params.provider}/${params.modelId}`,
|
||||||
|
channel: runtimeChannel,
|
||||||
|
capabilities: runtimeCapabilities,
|
||||||
|
},
|
||||||
|
});
|
||||||
const isDefaultAgent = sessionAgentId === defaultAgentId;
|
const isDefaultAgent = sessionAgentId === defaultAgentId;
|
||||||
const promptMode = isSubagentSessionKey(params.sessionKey) ? "minimal" : "full";
|
const promptMode = isSubagentSessionKey(params.sessionKey) ? "minimal" : "full";
|
||||||
const docsPath = await resolveClawdbotDocsPath({
|
const docsPath = await resolveClawdbotDocsPath({
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function buildEmbeddedSystemPrompt(params: {
|
|||||||
/** Controls which hardcoded sections to include. Defaults to "full". */
|
/** Controls which hardcoded sections to include. Defaults to "full". */
|
||||||
promptMode?: PromptMode;
|
promptMode?: PromptMode;
|
||||||
runtimeInfo: {
|
runtimeInfo: {
|
||||||
|
agentId?: string;
|
||||||
host: string;
|
host: string;
|
||||||
os: string;
|
os: string;
|
||||||
arch: string;
|
arch: string;
|
||||||
|
|||||||
44
src/agents/system-prompt-params.ts
Normal file
44
src/agents/system-prompt-params.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
|
import {
|
||||||
|
formatUserTime,
|
||||||
|
resolveUserTimeFormat,
|
||||||
|
resolveUserTimezone,
|
||||||
|
type ResolvedTimeFormat,
|
||||||
|
} from "./date-time.js";
|
||||||
|
|
||||||
|
export type RuntimeInfoInput = {
|
||||||
|
agentId?: string;
|
||||||
|
host: string;
|
||||||
|
os: string;
|
||||||
|
arch: string;
|
||||||
|
node: string;
|
||||||
|
model: string;
|
||||||
|
channel?: string;
|
||||||
|
capabilities?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SystemPromptRuntimeParams = {
|
||||||
|
runtimeInfo: RuntimeInfoInput;
|
||||||
|
userTimezone: string;
|
||||||
|
userTime?: string;
|
||||||
|
userTimeFormat?: ResolvedTimeFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildSystemPromptParams(params: {
|
||||||
|
config?: ClawdbotConfig;
|
||||||
|
agentId?: string;
|
||||||
|
runtime: Omit<RuntimeInfoInput, "agentId">;
|
||||||
|
}): SystemPromptRuntimeParams {
|
||||||
|
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
|
||||||
|
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
|
||||||
|
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
|
||||||
|
return {
|
||||||
|
runtimeInfo: {
|
||||||
|
agentId: params.agentId,
|
||||||
|
...params.runtime,
|
||||||
|
},
|
||||||
|
userTimezone,
|
||||||
|
userTime,
|
||||||
|
userTimeFormat,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { buildAgentSystemPrompt } from "./system-prompt.js";
|
import { buildAgentSystemPrompt, buildRuntimeLine } from "./system-prompt.js";
|
||||||
|
|
||||||
describe("buildAgentSystemPrompt", () => {
|
describe("buildAgentSystemPrompt", () => {
|
||||||
it("includes owner numbers when provided", () => {
|
it("includes owner numbers when provided", () => {
|
||||||
@@ -252,6 +252,22 @@ describe("buildAgentSystemPrompt", () => {
|
|||||||
expect(prompt).toContain("capabilities=inlineButtons");
|
expect(prompt).toContain("capabilities=inlineButtons");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes agent id in runtime when provided", () => {
|
||||||
|
const prompt = buildAgentSystemPrompt({
|
||||||
|
workspaceDir: "/tmp/clawd",
|
||||||
|
runtimeInfo: {
|
||||||
|
agentId: "work",
|
||||||
|
host: "host",
|
||||||
|
os: "macOS",
|
||||||
|
arch: "arm64",
|
||||||
|
node: "v20",
|
||||||
|
model: "anthropic/claude",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(prompt).toContain("agent=work");
|
||||||
|
});
|
||||||
|
|
||||||
it("includes reasoning visibility hint", () => {
|
it("includes reasoning visibility hint", () => {
|
||||||
const prompt = buildAgentSystemPrompt({
|
const prompt = buildAgentSystemPrompt({
|
||||||
workspaceDir: "/tmp/clawd",
|
workspaceDir: "/tmp/clawd",
|
||||||
@@ -263,6 +279,31 @@ describe("buildAgentSystemPrompt", () => {
|
|||||||
expect(prompt).toContain("/status shows Reasoning");
|
expect(prompt).toContain("/status shows Reasoning");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("builds runtime line with agent and channel details", () => {
|
||||||
|
const line = buildRuntimeLine(
|
||||||
|
{
|
||||||
|
agentId: "work",
|
||||||
|
host: "host",
|
||||||
|
os: "macOS",
|
||||||
|
arch: "arm64",
|
||||||
|
node: "v20",
|
||||||
|
model: "anthropic/claude",
|
||||||
|
},
|
||||||
|
"telegram",
|
||||||
|
["inlineButtons"],
|
||||||
|
"low",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(line).toContain("agent=work");
|
||||||
|
expect(line).toContain("host=host");
|
||||||
|
expect(line).toContain("os=macOS (arm64)");
|
||||||
|
expect(line).toContain("node=v20");
|
||||||
|
expect(line).toContain("model=anthropic/claude");
|
||||||
|
expect(line).toContain("channel=telegram");
|
||||||
|
expect(line).toContain("capabilities=inlineButtons");
|
||||||
|
expect(line).toContain("thinking=low");
|
||||||
|
});
|
||||||
|
|
||||||
it("describes sandboxed runtime and elevated when allowed", () => {
|
it("describes sandboxed runtime and elevated when allowed", () => {
|
||||||
const prompt = buildAgentSystemPrompt({
|
const prompt = buildAgentSystemPrompt({
|
||||||
workspaceDir: "/tmp/clawd",
|
workspaceDir: "/tmp/clawd",
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ export function buildAgentSystemPrompt(params: {
|
|||||||
/** Controls which hardcoded sections to include. Defaults to "full". */
|
/** Controls which hardcoded sections to include. Defaults to "full". */
|
||||||
promptMode?: PromptMode;
|
promptMode?: PromptMode;
|
||||||
runtimeInfo?: {
|
runtimeInfo?: {
|
||||||
|
agentId?: string;
|
||||||
host?: string;
|
host?: string;
|
||||||
os?: string;
|
os?: string;
|
||||||
arch?: string;
|
arch?: string;
|
||||||
@@ -546,27 +547,40 @@ export function buildAgentSystemPrompt(params: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push(
|
lines.push("## Runtime", buildRuntimeLine(runtimeInfo, runtimeChannel, runtimeCapabilities, params.defaultThinkLevel), `Reasoning: ${reasoningLevel} (hidden unless on/stream). Toggle /reasoning; /status shows Reasoning when enabled.`);
|
||||||
"## Runtime",
|
|
||||||
`Runtime: ${[
|
|
||||||
runtimeInfo?.host ? `host=${runtimeInfo.host}` : "",
|
|
||||||
runtimeInfo?.os
|
|
||||||
? `os=${runtimeInfo.os}${runtimeInfo?.arch ? ` (${runtimeInfo.arch})` : ""}`
|
|
||||||
: runtimeInfo?.arch
|
|
||||||
? `arch=${runtimeInfo.arch}`
|
|
||||||
: "",
|
|
||||||
runtimeInfo?.node ? `node=${runtimeInfo.node}` : "",
|
|
||||||
runtimeInfo?.model ? `model=${runtimeInfo.model}` : "",
|
|
||||||
runtimeChannel ? `channel=${runtimeChannel}` : "",
|
|
||||||
runtimeChannel
|
|
||||||
? `capabilities=${runtimeCapabilities.length > 0 ? runtimeCapabilities.join(",") : "none"}`
|
|
||||||
: "",
|
|
||||||
`thinking=${params.defaultThinkLevel ?? "off"}`,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(" | ")}`,
|
|
||||||
`Reasoning: ${reasoningLevel} (hidden unless on/stream). Toggle /reasoning; /status shows Reasoning when enabled.`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return lines.filter(Boolean).join("\n");
|
return lines.filter(Boolean).join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildRuntimeLine(
|
||||||
|
runtimeInfo: {
|
||||||
|
agentId?: string;
|
||||||
|
host?: string;
|
||||||
|
os?: string;
|
||||||
|
arch?: string;
|
||||||
|
node?: string;
|
||||||
|
model?: string;
|
||||||
|
},
|
||||||
|
runtimeChannel?: string,
|
||||||
|
runtimeCapabilities: string[] = [],
|
||||||
|
defaultThinkLevel?: ThinkLevel,
|
||||||
|
): string {
|
||||||
|
return `Runtime: ${[
|
||||||
|
runtimeInfo?.agentId ? `agent=${runtimeInfo.agentId}` : "",
|
||||||
|
runtimeInfo?.host ? `host=${runtimeInfo.host}` : "",
|
||||||
|
runtimeInfo?.os
|
||||||
|
? `os=${runtimeInfo.os}${runtimeInfo?.arch ? ` (${runtimeInfo.arch})` : ""}`
|
||||||
|
: runtimeInfo?.arch
|
||||||
|
? `arch=${runtimeInfo.arch}`
|
||||||
|
: "",
|
||||||
|
runtimeInfo?.node ? `node=${runtimeInfo.node}` : "",
|
||||||
|
runtimeInfo?.model ? `model=${runtimeInfo.model}` : "",
|
||||||
|
runtimeChannel ? `channel=${runtimeChannel}` : "",
|
||||||
|
runtimeChannel
|
||||||
|
? `capabilities=${runtimeCapabilities.length > 0 ? runtimeCapabilities.join(",") : "none"}`
|
||||||
|
: "",
|
||||||
|
`thinking=${defaultThinkLevel ?? "off"}`,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" | ")}`;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user