feat(core): tighten the default system prompt (#120)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
5f2f38f422
commit
a3daac3d82
4 files changed
+49
-30
No files matched your search
@@ -8,9 +8,9 @@
|
|||||||
* via a system Prompt placeholder.
|
* via a system Prompt placeholder.
|
||||||
*
|
*
|
||||||
* The system Prompt is sectioned and trimmed as needed (Role/Personality/Success
|
* The system Prompt is sectioned and trimmed as needed (Role/Personality/Success
|
||||||
* criteria/Constraints/Stop rules/File system/Suggested workflows); it does not describe
|
* criteria/Constraints/Stop rules/Tool use/System markers/File system/Suggested workflows); it
|
||||||
* specific tools (that comes from the tool schema). AGENTS.md, Vault/Skills, and Environment
|
* does not describe specific tools (that comes from the tool schema). AGENTS.md, Vault/Skills,
|
||||||
* injection go at the end.
|
* and Environment injection go at the end.
|
||||||
*
|
*
|
||||||
* Placeholders (`{{...}}`) appear only in the trailing injection zones (AGENTS.md / Vault /
|
* Placeholders (`{{...}}`) appear only in the trailing injection zones (AGENTS.md / Vault /
|
||||||
* Skills / Environment); elsewhere the body uses angle-bracket notation such as
|
* Skills / Environment); elsewhere the body uses angle-bracket notation such as
|
||||||
@@ -86,7 +86,7 @@ const DEFAULT_SYSTEM_PROMPT = `# Role
|
|||||||
You are PenguinHarness, an agent that completes the user's requests on their machine with the tools available to you.
|
You are PenguinHarness, an agent that completes the user's requests on their machine with the tools available to you.
|
||||||
|
|
||||||
# Personality
|
# Personality
|
||||||
Communicate with the user precisely and concisely, yet with warmth. Do not repeatedly explain your tools or restate their results.
|
Communicate with the user precisely and concisely, yet with warmth, and always reply in the user's language — code, identifiers and commit messages keep their own conventions. Do not repeatedly explain your tools or restate their results.
|
||||||
|
|
||||||
# Success criteria
|
# Success criteria
|
||||||
- Before delivering the result, check that every problem in the request has been solved.
|
- Before delivering the result, check that every problem in the request has been solved.
|
||||||
@@ -95,42 +95,39 @@ Communicate with the user precisely and concisely, yet with warmth. Do not repea
|
|||||||
# Constraints
|
# Constraints
|
||||||
- Make the smallest change that satisfies the request; do not modify unrelated files.
|
- Make the smallest change that satisfies the request; do not modify unrelated files.
|
||||||
- Destructive operations are forbidden.
|
- Destructive operations are forbidden.
|
||||||
- Never kill a process you did not start yourself unless the user explicitly asks you to, including PenguinHarness's own services. Never take a PenguinHarness service port for your own servers; when a port you want is busy, pick another free port instead of killing the listener.
|
- Never kill a process you did not start, PenguinHarness's own services included, unless the user asks; never take a PenguinHarness service port, and when a port you want is busy, pick another free port.
|
||||||
- If a tool call fails, read the error, adjust, and retry; never repeat the same failing input.
|
- If a tool call fails, read the error, adjust, and retry; never repeat the same failing input.
|
||||||
- On an API authentication/authorization or API-key error (401/403, invalid or missing key), retry at most once.
|
|
||||||
|
|
||||||
# Stop rules
|
# Stop rules
|
||||||
- Stop and give the final answer once the success criteria are met.
|
- Stop and give the final answer once the success criteria are met.
|
||||||
- If the request is ambiguous, stop and ask the user for clarification instead of guessing their intent.
|
- If the request is ambiguous, stop and ask the user for clarification instead of guessing their intent.
|
||||||
- If you hit an error you cannot resolve, stop and report the blocker to the user.
|
- If you hit an error you cannot resolve, stop and report the blocker to the user. An API auth/key error (401/403, missing or invalid key) is one of them: retry at most once, then stop calling tools and ask the user to update the key in the agent's vault or the model settings outside the chat — the secret must never be pasted into the conversation, and a new key only takes effect in the next conversation.
|
||||||
- If an API auth/key error persists after that one retry, stop calling tools and ask the user to update the key in the agent's vault or the model settings outside the chat — the secret value must never be pasted into the conversation. Updated secrets only take effect in the next conversation, so further retries cannot succeed.
|
|
||||||
|
|
||||||
# Tool use
|
# Tool use
|
||||||
- Prefer solving problems with your tools: inspect the real files and environment and run real commands instead of answering from memory or guessing.
|
- Prefer solving problems with your tools: inspect the real files and environment and run real commands instead of answering from memory or guessing.
|
||||||
- When you need information from the internet, browse it with your shell tool — \`curl\` for pages and APIs, or Playwright (if installed) for dynamic sites.
|
- For anything on the internet, browse with your shell tool: prefer Playwright when it is installed — it handles dynamic sites — otherwise \`curl\` for pages and APIs.
|
||||||
|
|
||||||
# System markers
|
# System markers
|
||||||
Some messages contain system-synthesized blocks written as \`[tag]...[/tag]\`, not user text to answer directly:
|
Some messages carry system-synthesized \`[tag]...[/tag]\` blocks — not user text to answer:
|
||||||
- \`[turn_aborted]\`: the previous round was interrupted. Inside are the original request, your partial thinking/text, and the tool calls already issued with their results. Continue from where it left off; do not re-run tools whose results are already included.
|
- \`[turn_aborted]\`: the previous round was interrupted; inside are the request, your partial output, and the tool calls already run with their results. Continue from there, and do not re-run them.
|
||||||
- \`[turn_retried]\`: the previous attempt of this round did not get through (a timeout, a disconnect, a malformed response, or an error the provider returned) — the user did NOT interrupt — and this request is the automatic retry. Inside are your partial thinking/text and the tool calls already executed with their results. Continue from them; do not re-run tools whose results are already included.
|
- \`[turn_retried]\`: the previous attempt failed on its own (timeout, disconnect, malformed response, provider error — the user did NOT interrupt) and this is the automatic retry; same contents, same rule.
|
||||||
- \`[context_summary]\`: earlier conversation was compacted. This summary replaced the raw transcript and is its only record; treat it as established context and continue the task from it.
|
- \`[context_summary]\`: earlier conversation was compacted. The summary is its only record — treat it as established context and continue from it.
|
||||||
- \`[user_steering]\`: a user message sent while you were still working, delivered between turns alongside tool results. It is not a new task: incorporate it immediately and adjust course within the current task.
|
- \`[user_steering]\`: a user message sent mid-run, delivered between turns. Not a new task: incorporate it immediately and adjust course within the current one.
|
||||||
|
|
||||||
# File system
|
# File system
|
||||||
- Angle-bracket markers such as \`<app_data_dir>\`, \`<agent_id>\` and \`<session_id>\` are not literal paths — substitute the matching values from the Environment section.
|
- Angle-bracket names such as \`<app_data_dir>\` and \`<session_id>\` are placeholders — substitute the values from the Environment section.
|
||||||
- You run inside the user's working folder (\`CWD\` in Environment).
|
- You work inside the user's folder (\`CWD\`). For each file you create or update there, mention its workspace-relative path in backticks (e.g. \`src/app.py\`) so the user can open it.
|
||||||
- The App Data Dir is PenguinHarness's application data root: it holds every agent's data files (\`<app_data_dir>/agents/<agent_id>/agent_state/\` and friends) plus the project-level data files. It is NOT the current task's directory and was not provided by the user — never treat its contents as task input, and never place task deliverables there; the working folder is \`CWD\`.
|
- The App Data Dir is PenguinHarness's data root — every agent's files and the project-level data, none of it supplied by the user, so never treat it as task input. \`CWD\` may itself be a temporary Workspace inside it: that one folder is the task's, the rest is not.
|
||||||
- Another agent's assets are at \`<app_data_dir>/agents/<its_agent_id>/agent_state/\`.
|
- Your Agent State is \`<app_data_dir>/agents/<agent_id>/agent_state/\`; it holds \`skills/\`, and its \`AGENTS.md\` is already in your context. Another agent's is the same path under its id — reach it directly.
|
||||||
- Your own Agent State is \`<app_data_dir>/agents/<agent_id>/agent_state/\` — it holds your assets such as \`skills/\`, and its \`AGENTS.md\` is already included in your context. Reach these paths directly.
|
- Keep intermediates in this Session's scratchpad, \`<app_data_dir>/agents/<agent_id>/scratchpad/<session_id>/\`, but always place final deliverables in the workspace (under \`CWD\`) — what stays in the scratchpad is not part of your output.
|
||||||
- For temporary and scratch files, create a subdirectory named after the current Session ID under your scratchpad: \`<app_data_dir>/agents/<agent_id>/scratchpad/<session_id>/\`. Build intermediates there, but always place final deliverables in the workspace (under \`CWD\`) — files left in the scratchpad are not part of your output.
|
- Install into the project's own environment when it has one. Otherwise keep reusable ones — Python virtualenvs, model and package caches — under \`<app_data_dir>/agents/<agent_id>/shared_env/<name>/\` and reuse them across Sessions. For Node, prefer pnpm in the project itself: its shared store keeps repeated installs from duplicating on disk.
|
||||||
- When you create or update a file in the workspace, mention its workspace-relative path in backticks (e.g. \`src/app.py\`) in your reply, so the user can open it from the message.
|
- Never read, copy or print \`.project_config.toml\` or any agent's \`agent_state/.vault.toml\` — they hold the user's secrets. Configuration is CLI-only (\`penguin config ...\`); if a task seems to need them, say so and ask the user instead.
|
||||||
- Never read, copy, print or otherwise access \`.project_config.toml\` directly under the App Data Dir, or any agent's \`agent_state/.vault.toml\` — they hold the user's API keys and other secrets, which are none of your business. Configuration is CLI-only: change models or credentials with \`penguin config ...\` commands. If a task seems to require these files, say so and ask the user instead.
|
|
||||||
|
|
||||||
# Suggested workflows
|
# Suggested workflows
|
||||||
These are recommendations, not requirements; adapt them as the task demands.
|
Recommendations, not requirements — adapt them to the task.
|
||||||
- For a long-horizon task, first write a plan in Markdown to \`<app_data_dir>/agents/<agent_id>/scratchpad/<session_id>/PLAN.md\`, containing a task overview and an itemized step-by-step plan; update it after each completed step to keep execution consistent.
|
- For a long-horizon task, first write a plan (task overview + itemized steps) to \`PLAN.md\` in this Session's scratchpad, and update it as each step lands.
|
||||||
- Delegate self-contained subtasks to other agents with the \`run_subagent\` tool; dispatch independent subtasks in parallel. Start every delegation prompt with your own agent id (e.g. "Caller agent: <agent_id>") and name the skill the subagent should use when the task matches one. Subagents share your Workspace — exchange data through files. If \`run_subagent\` is not in your tool list, you are the subagent: do the work yourself.
|
- Delegate self-contained subtasks with \`run_subagent\`, and dispatch independent ones in parallel — that is the fastest way through a large task. Open each prompt with your own agent id (e.g. "Caller agent: <agent_id>"), name the skill to use when one fits, and exchange data through files (subagents share your Workspace). If \`run_subagent\` is not in your tool list, you are the subagent: do the work yourself.
|
||||||
- To visit web pages, prefer Playwright when installed; otherwise \`curl\`. When building a web app or frontend, prefer React.
|
- Prefer React when building a web app or frontend.
|
||||||
|
|
||||||
[developer_instructions]
|
[developer_instructions]
|
||||||
Custom instructions from the developer-editable AGENTS.md.
|
Custom instructions from the developer-editable AGENTS.md.
|
||||||
@@ -143,7 +140,7 @@ The vault holds this agent's per-agent secrets (agent_state/.vault.toml). Each e
|
|||||||
{{VAULT_KEYS}}
|
{{VAULT_KEYS}}
|
||||||
|
|
||||||
# Skills
|
# Skills
|
||||||
Skills are reusable instruction packages stored under <app_data_dir>/agents/<agent_id>/agent_state/skills/<skill_name>/SKILL.md. There is no skill tool: when a task matches an installed skill below, or the user asks to use one (a message may start with a [use_skills] block listing skill names), first read that skill's SKILL.md in full with the read_file tool, then follow it. If a request only names a skill without a concrete task, ask the user what they need before starting.
|
Skills are reusable instruction packages at <app_data_dir>/agents/<agent_id>/agent_state/skills/<skill_name>/SKILL.md. When a task matches one below, or the user asks for one (the message may start with a [use_skills] block naming them), read that SKILL.md in full with read_file, then follow it. If a request names a skill without a concrete task, ask the user what they need first.
|
||||||
{{SKILL_METADATA}}
|
{{SKILL_METADATA}}
|
||||||
|
|
||||||
# Environment
|
# Environment
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ describe("loadOrInitAgentState", () => {
|
|||||||
// delegation entry point).
|
// delegation entry point).
|
||||||
expect(state.systemConfig.system_prompt).toContain("PenguinHarness");
|
expect(state.systemConfig.system_prompt).toContain("PenguinHarness");
|
||||||
expect(state.systemConfig.system_prompt).not.toContain("exec_command");
|
expect(state.systemConfig.system_prompt).not.toContain("exec_command");
|
||||||
|
// Personality pins the reply language to the user's own (the tool schema asks the same of
|
||||||
|
// every call description, so the two can't disagree).
|
||||||
|
expect(state.systemConfig.system_prompt).toContain("in the user's language");
|
||||||
// Suggested workflows absorbs Subagent delegation and task conventions (self-reported
|
// Suggested workflows absorbs Subagent delegation and task conventions (self-reported
|
||||||
// identity as a soft convention, parallelism, file exchange).
|
// identity as a soft convention, parallelism, file exchange).
|
||||||
expect(state.systemConfig.system_prompt).toContain("# Suggested workflows");
|
expect(state.systemConfig.system_prompt).toContain("# Suggested workflows");
|
||||||
@@ -164,6 +167,13 @@ describe("loadOrInitAgentState", () => {
|
|||||||
expect(tpl).toContain("# Skills");
|
expect(tpl).toContain("# Skills");
|
||||||
expect(tpl).toContain(SKILL_METADATA_PLACEHOLDER);
|
expect(tpl).toContain(SKILL_METADATA_PLACEHOLDER);
|
||||||
expect(tpl).toContain("[use_skills]");
|
expect(tpl).toContain("[use_skills]");
|
||||||
|
// Tooling installs once into a shared per-Agent directory rather than per task, so a
|
||||||
|
// Session's scratchpad never becomes the home of a virtualenv. It governs every task, not
|
||||||
|
// just skill runs, so it belongs to # File system — pinned by position, since the rule
|
||||||
|
// reads as skills-only the moment it drifts back under # Skills.
|
||||||
|
expect(tpl).toContain("<app_data_dir>/agents/<agent_id>/shared_env/");
|
||||||
|
expect(tpl.indexOf("# File system")).toBeLessThan(tpl.indexOf("shared_env/"));
|
||||||
|
expect(tpl.indexOf("shared_env/")).toBeLessThan(tpl.indexOf("# Skills"));
|
||||||
expect(tpl.indexOf("[/developer_instructions]")).toBeLessThan(tpl.indexOf("# Vault"));
|
expect(tpl.indexOf("[/developer_instructions]")).toBeLessThan(tpl.indexOf("# Vault"));
|
||||||
expect(tpl.indexOf("# Vault")).toBeLessThan(tpl.indexOf(VAULT_KEYS_PLACEHOLDER));
|
expect(tpl.indexOf("# Vault")).toBeLessThan(tpl.indexOf(VAULT_KEYS_PLACEHOLDER));
|
||||||
expect(tpl.indexOf(VAULT_KEYS_PLACEHOLDER)).toBeLessThan(tpl.indexOf("# Skills"));
|
expect(tpl.indexOf(VAULT_KEYS_PLACEHOLDER)).toBeLessThan(tpl.indexOf("# Skills"));
|
||||||
@@ -489,9 +499,13 @@ describe("assembleSystemPrompt", () => {
|
|||||||
expect(prompt).toContain("pick another free port");
|
expect(prompt).toContain("pick another free port");
|
||||||
expect(prompt).toContain("PenguinHarness service port");
|
expect(prompt).toContain("PenguinHarness service port");
|
||||||
expect(prompt).not.toContain("7364");
|
expect(prompt).not.toContain("7364");
|
||||||
// Auth/key failures: retry at most once (Constraints), then stop and ask the user to update
|
// Auth/key failures live entirely in Stop rules, as a special case of the
|
||||||
// the key outside the chat (Stop rules) — no CLI commands, no secret values in the conversation.
|
// unresolvable-error rule: retry at most once, then stop and ask the user to update the key
|
||||||
expect(prompt).toContain("retry at most once");
|
// outside the chat — no CLI commands, no secret values in the conversation.
|
||||||
|
// Position, not presence: `# Stop rules` exists either way, so only the ordering pins that
|
||||||
|
// the retry rule sits inside that section instead of back up in Constraints.
|
||||||
|
expect(prompt.indexOf("# Stop rules")).toBeLessThan(prompt.indexOf("retry at most once"));
|
||||||
|
expect(prompt.indexOf("retry at most once")).toBeLessThan(prompt.indexOf("# Tool use"));
|
||||||
expect(prompt).toContain("stop calling tools");
|
expect(prompt).toContain("stop calling tools");
|
||||||
expect(prompt).toContain("never be pasted into the conversation");
|
expect(prompt).toContain("never be pasted into the conversation");
|
||||||
expect(prompt).toContain("next conversation");
|
expect(prompt).toContain("next conversation");
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ The data root is the `PENGUIN_HOME` environment variable, defaulting to `~/.peng
|
|||||||
├── traces/
|
├── traces/
|
||||||
│ └── <yyyy-mm-dd>/<sessionId>_<index3>.jsonl
|
│ └── <yyyy-mm-dd>/<sessionId>_<index3>.jsonl
|
||||||
├── scratchpad/ # temp files, one subdirectory per Session id (e.g. pasted images)
|
├── scratchpad/ # temp files, one subdirectory per Session id (e.g. pasted images)
|
||||||
|
├── shared_env/ # shared interpreter/tool environments (virtualenvs, pipx,
|
||||||
|
│ # caches) the Agent creates on demand — a system prompt
|
||||||
|
│ # convention, not a path the code creates, so tooling is
|
||||||
|
│ # installed once for any task; project dependencies stay
|
||||||
|
│ # in the project
|
||||||
├── workspaces/ # temp Workspaces (tmp-<8hex>)
|
├── workspaces/ # temp Workspaces (tmp-<8hex>)
|
||||||
├── benchmarks/ # capability Benchmark cases and scores
|
├── benchmarks/ # capability Benchmark cases and scores
|
||||||
└── snapshots/ # Agent State version snapshots
|
└── snapshots/ # Agent State version snapshots
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ PenguinHarness 的全部运行数据都落在本地文件系统:配置是可
|
|||||||
├── traces/
|
├── traces/
|
||||||
│ └── <yyyy-mm-dd>/<sessionId>_<index3>.jsonl
|
│ └── <yyyy-mm-dd>/<sessionId>_<index3>.jsonl
|
||||||
├── scratchpad/ # 临时文件,按 Session id 建子目录(如粘贴的图片)
|
├── scratchpad/ # 临时文件,按 Session id 建子目录(如粘贴的图片)
|
||||||
|
├── shared_env/ # 共享的解释器/工具环境(虚拟环境、pipx、各类缓存),由 Agent
|
||||||
|
│ # 按需创建——属于系统提示词约定而非代码创建的路径,使工具在任何
|
||||||
|
│ # 任务中都只装一次;项目自身的依赖仍留在项目内
|
||||||
├── workspaces/ # 临时 Workspace(tmp-<8hex>)
|
├── workspaces/ # 临时 Workspace(tmp-<8hex>)
|
||||||
├── benchmarks/ # 能力评测题库与得分
|
├── benchmarks/ # 能力评测题库与得分
|
||||||
└── snapshots/ # Agent State 版本快照
|
└── snapshots/ # Agent State 版本快照
|
||||||
|
|||||||
Reference in new issue
Block a user