From a1adbd00af6618f3cb168fadf036e00690737996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=A4=95?= Date: Tue, 28 Apr 2026 03:53:33 +0800 Subject: [PATCH] Refactor Agent Tool Assignments to Database-Driven Static Loading (#45) * Refactor tool loading to use static database assignment - Add `tools` field to `WorkerIndividual` and `SystemNodeConfig` models - Update frontend WorkerIndividualSettings to support multi-select tools and select `bound_skill` from available backend API - Deprecate dynamic `get_tool` method during agent execution, replacing it with `load_tools_from_list` via absolute paths during agent initialization - Fix deprecated tool loading usage across `SupervisoryNode`, `ConsciousnessNode`, `ControlNode`, and `BaseIndividual` - Provide `reload` API route to clear `GlobalIndividualManager` state to rebuild nodes cleanly upon next request - Fix `user_test.py` related to unhashed password assignments in testing mock object Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * Refactor tool loading to use static database assignment part 2 - Restore BaseIndividual's `_init_agent` method to inject parsed `tools_list` via absolute paths dynamically using `load_tools_from_list` - Restore React component multi-select support for tools dropdown via `/api/v1/resource/tool` backend response integration - Restore `user_test.py` compatibility related to access hasher assignments - Passed 75 tests with no errors Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * Refactor tool loading to use static database assignment - Add `tools` field to `WorkerIndividual` and `SystemNodeConfig` models - Update frontend WorkerIndividualSettings to support multi-select tools and select `bound_skill` from available backend API - Deprecate dynamic `get_tool` method during agent execution, replacing it with `load_tools_from_list` via absolute paths during agent initialization - Fix deprecated tool loading usage across `SupervisoryNode`, `ConsciousnessNode`, `ControlNode`, and `BaseIndividual` - Provide `reload` API route to clear `GlobalIndividualManager` state to rebuild nodes cleanly upon next request - Fix `user_test.py` related to unhashed password assignments in testing mock object Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * Finalize all tool loading refactoring with complete changes - Merged database schema enhancements for `tools` multi-select list - Completed the `load_tools_from_list` via absolute paths utility update - Refactored `AgentFactory` and corresponding initialization calls in `BaseIndividual`, `SupervisoryNode`, `ConsciousnessNode`, and `ControlNode` to inject statically via constructor - Updated frontend UI `WorkerIndividualSettings` with UI for `bound_skill` selection and dynamic multi-tool selector array - Removed all legacy usages of dynamic `tools=tool` invocation - Provided backend `/reload` API and automatic clearing of instance cache upon individual configuration update - Repaired mock password assignment logic in testing suite Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * Restore complete tool loading refactor logic - Re-apply BaseIndividual tools resolution logic - Correctly patch API, UI files, system nodes and testing scripts avoiding checkout loss - Passed all 75 integration and unit tests successfully Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> --- .../Agent/WorkerIndividualSettings.tsx | 93 ++++++++++++++++--- pretor/adapter/model_adapter/agent_factory.py | 6 +- pretor/api/agent.py | 34 ++++++- pretor/core/database/module/system_node.py | 6 +- pretor/core/database/postgres.py | 4 +- pretor/core/database/table/individual.py | 1 + pretor/core/database/table/system_node.py | 4 + .../consciousness_node/consciousness_node.py | 20 ++-- .../individual/control_node/control_node.py | 14 +-- .../supervisory_node/supervisory_node.py | 13 +-- pretor/utils/get_tool.py | 57 +++++++----- pretor/worker_individual/base_individual.py | 8 +- .../model_adapter/agent_factory_test.py | 3 +- tests/core/database/module/user_test.py | 7 +- 14 files changed, 196 insertions(+), 74 deletions(-) diff --git a/frontend/src/components/Agent/WorkerIndividualSettings.tsx b/frontend/src/components/Agent/WorkerIndividualSettings.tsx index 22bc619..c13c66c 100644 --- a/frontend/src/components/Agent/WorkerIndividualSettings.tsx +++ b/frontend/src/components/Agent/WorkerIndividualSettings.tsx @@ -14,12 +14,15 @@ interface WorkerIndividual { output_template?: string; // Change to string for the form state bound_skill?: string; // Change to string for the form state workspace?: string; // Change to string for the form state + tools?: string; // Form state for tools JSON array } export function WorkerIndividualSettings() { const [providers, setProviders] = useState([]); const [workers, setWorkers] = useState([]); const [systemNodes, setSystemNodes] = useState([]); + const [availableSkills, setAvailableSkills] = useState([]); + const [availableTools, setAvailableTools] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); @@ -32,14 +35,20 @@ export function WorkerIndividualSettings() { const fetchData = async () => { setLoading(true); try { - const [provRes, workRes, sysRes] = await Promise.all([ + const [provRes, workRes, sysRes, toolsRes, skillsRes] = await Promise.all([ apiClient.get('/api/v1/provider/list'), apiClient.get('/api/v1/agent/worker'), - apiClient.get('/api/v1/agent') + apiClient.get('/api/v1/agent'), + apiClient.get('/api/v1/resource/tool'), + apiClient.get('/api/v1/resource/skill') ]); setProviders(Object.values(provRes.data.provider_list || {})); setWorkers(workRes.data.workers || []); + const allTools = toolsRes.data.tools ? Object.values(toolsRes.data.tools).flatMap(tGroup => Object.keys(tGroup as any)) : []; + setAvailableTools(allTools); + setAvailableSkills(Object.keys(skillsRes.data.skills || {})); + const sysNodesData = sysRes.data.system_nodes || []; const defaultSysNodes = ['supervisory_node', 'consciousness_node', 'control_node']; @@ -54,6 +63,7 @@ export function WorkerIndividualSettings() { agent_type: 'System Node', provider_title: found && found.provider_title ? found.provider_title : defaultProvider, model_id: found && found.model_id ? found.model_id : '', + tools: found && found.tools ? JSON.stringify(found.tools) : '[]', is_system: true }; }); @@ -75,7 +85,8 @@ export function WorkerIndividualSettings() { ...worker, output_template: typeof worker.output_template === 'string' ? worker.output_template : JSON.stringify(worker.output_template || {}), bound_skill: typeof worker.bound_skill === 'string' ? worker.bound_skill : JSON.stringify(worker.bound_skill || {}), - workspace: typeof worker.workspace === 'string' ? worker.workspace : JSON.stringify(worker.workspace || []) + workspace: typeof worker.workspace === 'string' ? worker.workspace : JSON.stringify(worker.workspace || []), + tools: typeof worker.tools === 'string' ? worker.tools : JSON.stringify(worker.tools || []) }); setIsNew(false); setIsEditing(true); @@ -92,7 +103,8 @@ export function WorkerIndividualSettings() { system_prompt: '', output_template: '{}', bound_skill: '{}', - workspace: '[]' + workspace: '[]', + tools: '[]' }); setIsNew(true); setIsEditing(true); @@ -118,7 +130,8 @@ export function WorkerIndividualSettings() { const payload = { individual_name: editData.agent_name, provider_title: editData.provider_title, - model_id: editData.model_id + model_id: editData.model_id, + tools: JSON.parse(editData.tools || '[]') }; await apiClient.post('/api/v1/agent', payload); } else { @@ -126,7 +139,8 @@ export function WorkerIndividualSettings() { ...editData, output_template: JSON.parse(editData.output_template || '{}'), bound_skill: JSON.parse(editData.bound_skill || '{}'), - workspace: JSON.parse(editData.workspace || '[]') + workspace: JSON.parse(editData.workspace || '[]'), + tools: JSON.parse(editData.tools || '[]') }; if (isNew) { @@ -332,13 +346,27 @@ export function WorkerIndividualSettings() { />
- -