Brain: inject identity into the live prompt + surface AGENTS.md in the command center
Gap 1 — the brain's identity sections were stored but UI-only. cm-runtime/brain.rs
`compose_system` now folds the brain's AGENTS.md ("## How I operate") + personality
into the live system prompt (after the Postgres-authoritative base, before skills +
memory; falls back to the brain's soul_md when the base is empty). Mirrors the
OpenClaw/ZeroClaw render order.
Mapping — expose `agent_md` on `GET /api/claws/{id}/brain` (ClawBrainResponse) and
render it as a collapsible "HOW I OPERATE · AGENTS.md" card in the command center's
BRAIN column (RawBrain gains agent_md; richBrain passes it through). So the section
that's now in the prompt is also visible in the UI.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
11a1f22daa
commit
9fca3f6676
@@ -148,6 +148,8 @@ pub struct ClawBrainResponse {
|
|||||||
/// Whether a `.brain` file already existed before this request.
|
/// Whether a `.brain` file already existed before this request.
|
||||||
pub exists: bool,
|
pub exists: bool,
|
||||||
pub system_prompt: Option<String>,
|
pub system_prompt: Option<String>,
|
||||||
|
/// AGENTS.md — "how I operate" (workflow/rules); folded into the live prompt.
|
||||||
|
pub agent_md: Option<String>,
|
||||||
pub personality: Option<String>,
|
pub personality: Option<String>,
|
||||||
pub skills: Vec<BrainSkill>,
|
pub skills: Vec<BrainSkill>,
|
||||||
pub tools: Vec<BrainTool>,
|
pub tools: Vec<BrainTool>,
|
||||||
@@ -205,6 +207,7 @@ fn load_brain(agent: &Agent, skills: &[(String, String)]) -> ClawBrainResponse {
|
|||||||
ClawBrainResponse {
|
ClawBrainResponse {
|
||||||
exists: existed,
|
exists: existed,
|
||||||
system_prompt: brain.system_prompt(),
|
system_prompt: brain.system_prompt(),
|
||||||
|
agent_md: brain.agent_md(),
|
||||||
personality: brain.personality(),
|
personality: brain.personality(),
|
||||||
skills: skills_v,
|
skills: skills_v,
|
||||||
tools: tools_v,
|
tools: tools_v,
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! Each turn we open the claw's local working `.brain` (cm-brain / ClawhDF5),
|
//! Each turn we open the claw's local working `.brain` (cm-brain / ClawhDF5),
|
||||||
//! recall relevant memory, record the user's turn, and compose a system prompt
|
//! recall relevant memory, record the user's turn, and compose a system prompt
|
||||||
//! that injects the claw's **skills** and **recalled memory** on top of its
|
//! that injects the claw's **identity** (AGENTS.md "how I operate" + personality),
|
||||||
//! Postgres-authoritative system prompt. Any failure falls back to the plain
|
//! **skills**, and **recalled memory** on top of its Postgres-authoritative system
|
||||||
//! prompt — the brain must never break chat.
|
//! prompt. Any failure falls back to the plain prompt — the brain must never break chat.
|
||||||
//!
|
//!
|
||||||
//! The local file is a working cache of the claw's brain (canonical home is
|
//! The local file is a working cache of the claw's brain (canonical home is
|
||||||
//! ClawBrainHub); memory accrues here and is pushed back on save/publish.
|
//! ClawBrainHub); memory accrues here and is pushed back on save/publish.
|
||||||
@@ -20,8 +20,8 @@ fn brain_dir() -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compose the system prompt for a claw, augmenting `base_prompt` with its
|
/// Compose the system prompt for a claw, augmenting `base_prompt` with its
|
||||||
/// skills + recalled memory, and recording the user turn. Best-effort: returns
|
/// identity (AGENTS.md + personality), skills, and recalled memory, and recording
|
||||||
/// `base_prompt` unchanged on any brain error.
|
/// the user turn. Best-effort: returns `base_prompt` unchanged on any brain error.
|
||||||
pub fn compose_system(
|
pub fn compose_system(
|
||||||
agent_id: &str,
|
agent_id: &str,
|
||||||
base_prompt: &str,
|
base_prompt: &str,
|
||||||
@@ -64,8 +64,28 @@ fn try_compose(
|
|||||||
// Record the user's turn so future sessions can recall it (best-effort).
|
// Record the user's turn so future sessions can recall it (best-effort).
|
||||||
let _ = brain.remember("user", user_text, session_label);
|
let _ = brain.remember("user", user_text, session_label);
|
||||||
|
|
||||||
let mut out = String::with_capacity(base_prompt.len() + 256);
|
let mut out = String::with_capacity(base_prompt.len() + 512);
|
||||||
|
// Base identity: the Postgres-authoritative system prompt, or — if it's empty
|
||||||
|
// (e.g. a brain pulled from the Hub that carries its identity in soul_md) —
|
||||||
|
// the brain's own system prompt (which falls back to soul_md).
|
||||||
|
if base_prompt.trim().is_empty() {
|
||||||
|
if let Some(sp) = brain.system_prompt() {
|
||||||
|
out.push_str(&sp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
out.push_str(base_prompt);
|
out.push_str(base_prompt);
|
||||||
|
}
|
||||||
|
// Identity sections stored in the brain but previously UI-only — now folded
|
||||||
|
// into the live prompt (mirrors the OpenClaw/ZeroClaw AGENTS.md + persona
|
||||||
|
// render order): "how I operate", then personality.
|
||||||
|
if let Some(agent_md) = brain.agent_md() {
|
||||||
|
out.push_str("\n\n## How I operate\n");
|
||||||
|
out.push_str(&agent_md);
|
||||||
|
}
|
||||||
|
if let Some(persona) = brain.personality() {
|
||||||
|
out.push_str("\n\n## Personality\n");
|
||||||
|
out.push_str(&persona);
|
||||||
|
}
|
||||||
if !skills.is_empty() {
|
if !skills.is_empty() {
|
||||||
out.push_str("\n\n## Your skills (apply them when relevant)\n");
|
out.push_str("\n\n## Your skills (apply them when relevant)\n");
|
||||||
for (name, body) in skills {
|
for (name, body) in skills {
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Activity, Brain, Camera, Cpu, Database, Drama, Settings, ShieldCheck, Wrench, Zap } from "lucide-react";
|
import { Activity, Brain, Camera, Cpu, Database, Drama, Settings, ShieldCheck, Workflow, Wrench, Zap } from "lucide-react";
|
||||||
|
|
||||||
import type { DemoAgent } from "@/lib/dashboard-demo";
|
import type { DemoAgent } from "@/lib/dashboard-demo";
|
||||||
import { useAgentTelemetry, useLiveEvent } from "@/lib/live/useClawmatesLive";
|
import { useAgentTelemetry, useLiveEvent } from "@/lib/live/useClawmatesLive";
|
||||||
import { AnatomyCard, PersonalityBody, SystemPromptCard, mono, tag, type RawBrain } from "./anatomy-cards";
|
import { AnatomyCard, MarkdownText, PersonalityBody, SystemPromptCard, mono, tag, type RawBrain } from "./anatomy-cards";
|
||||||
import { AvatarModal } from "./AvatarModal";
|
import { AvatarModal } from "./AvatarModal";
|
||||||
import { AddToolModal } from "./AddToolModal";
|
import { AddToolModal } from "./AddToolModal";
|
||||||
|
|
||||||
@@ -232,6 +232,11 @@ export function ClawCommandCenter({
|
|||||||
{/* BRAIN */}
|
{/* BRAIN */}
|
||||||
<div style={colStyle}>
|
<div style={colStyle}>
|
||||||
<SystemPromptCard prompt={agent.systemPrompt} />
|
<SystemPromptCard prompt={agent.systemPrompt} />
|
||||||
|
{brain?.agent_md ? (
|
||||||
|
<AnatomyCard tint="#ff8a7a" label="HOW I OPERATE · AGENTS.md" icon={<Workflow size={15} />} collapsible>
|
||||||
|
<MarkdownText text={brain.agent_md} baseSize={13.5} />
|
||||||
|
</AnatomyCard>
|
||||||
|
) : null}
|
||||||
<AnatomyCard tint="#c98af0" label="PERSONALITY" icon={<Drama size={15} />} collapsible>
|
<AnatomyCard tint="#c98af0" label="PERSONALITY" icon={<Drama size={15} />} collapsible>
|
||||||
<PersonalityBody raw={brain?.personality} fallback={c.personality} />
|
<PersonalityBody raw={brain?.personality} fallback={c.personality} />
|
||||||
</AnatomyCard>
|
</AnatomyCard>
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ type RawApp = { id: string; name: string; category?: string };
|
|||||||
type RawBrain = {
|
type RawBrain = {
|
||||||
exists: boolean;
|
exists: boolean;
|
||||||
system_prompt: string | null;
|
system_prompt: string | null;
|
||||||
|
agent_md: string | null;
|
||||||
personality: string | null;
|
personality: string | null;
|
||||||
skills: { name: string; body: string }[];
|
skills: { name: string; body: string }[];
|
||||||
tools: { name: string; state: string }[];
|
tools: { name: string; state: string }[];
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const mono = "'JetBrains Mono', ui-monospace, monospace";
|
|||||||
export type RawBrain = {
|
export type RawBrain = {
|
||||||
exists: boolean;
|
exists: boolean;
|
||||||
system_prompt: string | null;
|
system_prompt: string | null;
|
||||||
|
agent_md: string | null;
|
||||||
personality: string | null;
|
personality: string | null;
|
||||||
skills: { name: string; body: string }[];
|
skills: { name: string; body: string }[];
|
||||||
tools: { name: string; state: string }[];
|
tools: { name: string; state: string }[];
|
||||||
|
|||||||
Reference in New Issue
Block a user