🐛 fix: group builder not set true edit data (#11858)

* feat: add the  setAgentBuilderContent tools into agent group builder to slove setEditor not work

* feat: update the system prompt
This commit is contained in:
Shinji-Li
2026-01-26 20:22:00 +08:00
committed by GitHub
parent ec854d7d55
commit 8eba0e654a
8 changed files with 125 additions and 19 deletions

View File

@@ -6,6 +6,7 @@ import { type GroupMemberConfig, chatGroupService } from '@/services/chatGroup';
import { useAgentStore } from '@/store/agent';
import { getChatGroupStoreState } from '@/store/agentGroup';
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
import { useGroupProfileStore } from '@/store/groupProfile';
import type {
BatchCreateAgentsParams,
@@ -410,6 +411,11 @@ export class GroupAgentBuilderExecutionRuntime {
// Refresh the group detail in the store to sync agent data
await state.refreshGroupDetail(groupId);
// IMPORTANT: Directly update the editor content instead of manipulating store data.
// This bypasses the priority issue between editorData (JSON) and systemRole (markdown).
// The editor will auto-save and sync both fields properly after the update.
useGroupProfileStore.getState().setAgentBuilderContent(agentId, prompt);
const content = prompt
? `Successfully updated agent ${agentId} system prompt (${prompt.length} characters)`
: `Successfully cleared agent ${agentId} system prompt`;
@@ -563,6 +569,11 @@ export class GroupAgentBuilderExecutionRuntime {
// Refresh the group detail in the store to ensure data sync
await state.refreshGroupDetail(group.id);
// IMPORTANT: Directly update the editor content instead of manipulating store data.
// This bypasses the priority issue between editorData (JSON) and content (markdown).
// The editor will auto-save and sync both fields properly after the update.
useGroupProfileStore.getState().setAgentBuilderContent(group.id, args.prompt);
const content = args.prompt
? `Successfully updated group shared prompt (${args.prompt.length} characters)`
: 'Successfully cleared group shared prompt';

View File

@@ -63,6 +63,13 @@ You have access to tools that can modify group configurations:
- User wants to change how a specific agent behaves → use \`updateAgentPrompt\` with that agent's ID
- User mentions "group prompt", "shared content", "background info" → use \`updateGroupPrompt\`
- User mentions "agent behavior", "agent prompt", specific agent name → use \`updateAgentPrompt\`
**CRITICAL - Individual Updates Only:**
- **NEVER batch update multiple agents with the same prompt** - each agent should have its own unique configuration
- **ALWAYS update agents individually** - use \`updateAgentPrompt\` with a specific agentId for each agent
- **ALWAYS update group prompt separately** - use \`updateGroupPrompt\` for shared content, never mix with agent prompts
- When modifying multiple agents, call \`updateAgentPrompt\` once for each agent with their specific agentId
- When modifying group content, call \`updateGroupPrompt\` separately - it applies to ALL members
</prompt_architecture>
<supervisor_prompt_generation>
@@ -176,13 +183,18 @@ When creating agents (via \`createAgent\` or \`batchCreateAgents\`), you MUST an
4. **Distinguish group vs agent operations**:
- Group-level: updateGroupPrompt, updateGroup, inviteAgent, removeAgent, batchCreateAgents
- Agent-level: updateAgentPrompt (requires agentId), updateConfig (agentId optional, defaults to supervisor), installPlugin
5. **CRITICAL - Auto-update supervisor after member changes**: After ANY member change (create, invite, remove), you MUST automatically call \`updateAgentPrompt\` with supervisor's agentId to regenerate the orchestration prompt. This is NOT optional - the supervisor needs updated delegation rules to coordinate the team effectively.
6. **CRITICAL - Assign tools when creating agents**: When using \`createAgent\` or \`batchCreateAgents\`, ALWAYS include appropriate \`tools\` based on the agent's role. Reference \`official_tools\` in the context for available tool identifiers. An agent without proper tools cannot perform specialized tasks.
7. **Explain your changes**: When modifying configurations, explain what you're changing and why it might benefit the group collaboration.
8. **Validate user intent**: For significant changes (like removing an agent), confirm with the user before proceeding.
9. **Provide recommendations**: When users ask for advice, consider how changes affect multi-agent collaboration.
10. **Use user's language**: Always respond in the same language the user is using.
11. **Cannot remove supervisor**: The supervisor agent cannot be removed from the group - it's the orchestrator.
5. **CRITICAL - Individual updates only**:
- When updating agent prompts, ALWAYS call \`updateAgentPrompt\` individually for each agent with their specific agentId
- When updating group prompt, ALWAYS call \`updateGroupPrompt\` separately - it affects ALL members
- NEVER try to batch update multiple agents with the same prompt - each agent needs individual configuration
- NEVER mix group prompt updates with agent prompt updates - they serve different purposes
6. **CRITICAL - Auto-update supervisor after member changes**: After ANY member change (create, invite, remove), you MUST automatically call \`updateAgentPrompt\` with supervisor's agentId to regenerate the orchestration prompt. This is NOT optional - the supervisor needs updated delegation rules to coordinate the team effectively.
7. **CRITICAL - Assign tools when creating agents**: When using \`createAgent\` or \`batchCreateAgents\`, ALWAYS include appropriate \`tools\` based on the agent's role. Reference \`official_tools\` in the context for available tool identifiers. An agent without proper tools cannot perform specialized tasks.
8. **Explain your changes**: When modifying configurations, explain what you're changing and why it might benefit the group collaboration.
9. **Validate user intent**: For significant changes (like removing an agent), confirm with the user before proceeding.
10. **Provide recommendations**: When users ask for advice, consider how changes affect multi-agent collaboration.
11. **Use user's language**: Always respond in the same language the user is using.
12. **Cannot remove supervisor**: The supervisor agent cannot be removed from the group - it's the orchestrator.
</guidelines>
<configuration_knowledge>
@@ -256,6 +268,24 @@ When creating agents (via \`createAgent\` or \`batchCreateAgents\`), you MUST an
- For member: Find agentId from \`<group_members>\`, then updateAgentPrompt with that agentId
</example>
<example title="Update Multiple Agents (Individual Updates Required)">
User: "Update the prompts for developer and designer agents"
Action (MUST update individually):
1. Find developer agentId from \`<group_members>\`
2. Call updateAgentPrompt with developer's agentId and their specific prompt
3. Find designer agentId from \`<group_members>\`
4. Call updateAgentPrompt with designer's agentId and their specific prompt
Note: Each agent gets a separate updateAgentPrompt call with unique content - NEVER use the same prompt for multiple agents
</example>
<example title="Update Both Group and Agent Prompts (Separate Updates)">
User: "Add project context and update supervisor's delegation rules"
Action (MUST update separately):
1. First - updateGroupPrompt: Add project background, domain knowledge (shared by ALL)
2. Second - updateAgentPrompt with supervisor's agentId: Add delegation rules (supervisor only)
Note: Group prompt and agent prompt are separate - NEVER combine them in one update
</example>
<example title="Update Configuration">
User: "Change model to Claude" / "Set welcome message"
Action:

View File

@@ -4,7 +4,7 @@ import { Button, Flexbox } from '@lobehub/ui';
import { Divider } from 'antd';
import { useTheme } from 'antd-style';
import { PlayIcon, Settings2Icon } from 'lucide-react';
import { memo, useCallback, useMemo, useState } from 'react';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join';
@@ -30,6 +30,8 @@ const GroupProfile = memo(() => {
const editor = useGroupProfileStore((s) => s.editor);
const handleContentChange = useGroupProfileStore((s) => s.handleContentChange);
const agentBuilderContentUpdate = useGroupProfileStore((s) => s.agentBuilderContentUpdate);
const setAgentBuilderContent = useGroupProfileStore((s) => s.setAgentBuilderContent);
// Create save callback that captures latest groupId
const saveContent = useCallback(
@@ -56,6 +58,18 @@ const GroupProfile = memo(() => {
[currentGroup?.content, currentGroup?.editorData],
);
// Watch for agent builder content updates and apply them directly to the editor
useEffect(() => {
if (!editor || !agentBuilderContentUpdate || !groupId) return;
if (agentBuilderContentUpdate.entityId !== groupId) return;
// Directly set the editor content
editor.setDocument('markdown', agentBuilderContentUpdate.content);
// Clear the update after processing to prevent re-applying
setAgentBuilderContent('', '');
}, [editor, agentBuilderContentUpdate, groupId, setAgentBuilderContent]);
return (
<>
<Flexbox

View File

@@ -4,7 +4,7 @@ import { Alert, Button, Flexbox, Icon } from '@lobehub/ui';
import { Divider } from 'antd';
import isEqual from 'fast-deep-equal';
import { InfoIcon, PlayIcon } from 'lucide-react';
import React, { memo, useCallback, useMemo } from 'react';
import React, { memo, useCallback, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join';
@@ -28,6 +28,8 @@ const MemberProfile = memo(() => {
const agentId = useGroupProfileStore((s) => s.activeTabId);
const editor = useGroupProfileStore((s) => s.editor);
const handleContentChange = useGroupProfileStore((s) => s.handleContentChange);
const agentBuilderContentUpdate = useGroupProfileStore((s) => s.agentBuilderContentUpdate);
const setAgentBuilderContent = useGroupProfileStore((s) => s.setAgentBuilderContent);
// Get agent config by agentId
const config = useAgentStore(agentByIdSelectors.getAgentConfigById(agentId), isEqual);
@@ -80,6 +82,18 @@ const MemberProfile = memo(() => {
[updateAgentConfigById, agentId],
);
// Watch for agent builder content updates and apply them directly to the editor
useEffect(() => {
if (!editor || !agentBuilderContentUpdate) return;
if (agentBuilderContentUpdate.entityId !== agentId) return;
// Directly set the editor content
editor.setDocument('markdown', agentBuilderContentUpdate.content);
// Clear the update after processing to prevent re-applying
setAgentBuilderContent('', '');
}, [editor, agentBuilderContentUpdate, agentId, setAgentBuilderContent]);
return (
<>
{/* External agent warning or AutoSaveHint */}

View File

@@ -22,13 +22,19 @@ const loadEditorContent = (
typeof editorData.editorData === 'object' &&
Object.keys(editorData.editorData as object).length > 0;
if (hasValidEditorData) {
editorInstance.setDocument('json', JSON.stringify(editorData.editorData));
return true;
} else if (editorData.content?.trim()) {
editorInstance.setDocument('markdown', editorData.content, { keepId: true });
return true;
try {
if (hasValidEditorData) {
editorInstance.setDocument('json', JSON.stringify(editorData.editorData));
return true;
} else if (editorData.content?.trim()) {
editorInstance.setDocument('markdown', editorData.content, { keepId: true });
return true;
}
} catch (err) {
console.error('[loadEditorContent] Error loading content:', err);
return false;
}
return false;
};
@@ -65,12 +71,12 @@ const EditorDataMode = memo<EditorDataModeProps>(
[editorData, entityId, onInit],
);
// Load content only when entityId changes (switching to a different entity)
// Ignore editorData changes for the same entity to prevent focus loss during auto-save
// Load content when entityId changes (switching to a different entity)
// Ignore editorData changes when entityId hasn't changed to prevent focus loss during auto-save
useEffect(() => {
if (!editor || !isEditorReadyRef.current) return;
// Only reload if entityId changed (switching entities)
// Only reload if entityId changed
if (!isEntityChanged) {
// Same entity - don't reload, user is still editing
return;
@@ -84,7 +90,7 @@ const EditorDataMode = memo<EditorDataModeProps>(
} catch (err) {
console.error('[EditorCanvas] Failed to load content:', err);
}
}, [editor, entityId, isEntityChanged, editorData]);
}, [editor, entityId, editorData, isEntityChanged]);
if (!editor) return null;

View File

@@ -115,8 +115,15 @@ const getAgentBuilderContextById =
};
};
/**
* Get full agent data by agentId
* Returns the complete agent object including metadata fields like updatedAt
*/
const getAgentById = (agentId: string) => (s: AgentStoreState) => s.agentMap[agentId];
export const agentByIdSelectors = {
getAgentBuilderContextById,
getAgentById,
getAgentConfigById: agentSelectors.getAgentConfigById,
getAgentEnableModeById,
getAgentFilesById,

View File

@@ -16,6 +16,11 @@ export interface Action {
flushSave: () => void;
handleContentChange: (saveCallback: (payload: SaveContentPayload) => Promise<void>) => void;
setActiveTabId: (tabId: string) => void;
/**
* Set content from agent builder - triggers editor to update
* @param entityId - groupId for group editor, agentId for member editor
*/
setAgentBuilderContent: (entityId: string, content: string) => void;
setChatPanelExpanded: (expanded: boolean | ((prev: boolean) => boolean)) => void;
updateSaveStatus: (tabId: string, status: SaveStatus) => void;
}
@@ -153,6 +158,16 @@ export const store: StateCreator<Store> = (set, get) => {
set({ activeTabId: tabId });
},
setAgentBuilderContent: (entityId, content) => {
set({
agentBuilderContentUpdate: {
content,
entityId,
timestamp: Date.now(),
},
});
},
setChatPanelExpanded: (expanded) => {
if (typeof expanded === 'function') {
set((state) => ({ chatPanelExpanded: expanded(state.chatPanelExpanded) }));

View File

@@ -15,6 +15,15 @@ export interface State extends PublicState {
* Active tab ID - 'group' for group settings, or agent ID for member editor
*/
activeTabId: string;
/**
* Agent builder content update - when set, triggers editor to load new content
* Format: { entityId: string (groupId or agentId), content: string, timestamp: number }
*/
agentBuilderContentUpdate?: {
content: string;
entityId: string;
timestamp: number;
};
chatPanelExpanded: boolean;
editor?: IEditor;
editorState?: any; // EditorState from useEditorState hook