Skip to main content

nexau-evolution-guide

NexAU agent evolution reference for a simple starting agent. Use when adding tools, middleware, sub-agents, or skills during evolution. Covers all available components, YAML config schema, and creation guides. Reference docs in reference/ for deep dives. Use when this capability is needed.

설치로 이동

소스 정보

저장소
tomevault-io/tomes
최근 소스 활동
2026년 7월 23일 21:48
감지된 SKILL.md 언어
영어
스타
1
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
nexau-evolution-guide
description
NexAU agent evolution reference for a simple starting agent. Use when adding tools, middleware, sub-agents, or skills during evolution. Covers all available components, YAML config schema, and creation guides. Reference docs in reference/ for deep dives. Use when this capability is needed.
metadata
{"author":"china-qijizhifeng"}
# NexAU Evolution Guide — Simple Agent Starting Point The code agent starts **simple**: a single `run_shell_command` tool, no middleware, no skills, no sub-agents. Evolution progressively adds components to improve performance. This guide covers **what you can add** and **how to add it**. ## Current Agent Baseline ```yaml # workspace/code_agent.yaml (starting state) type: agent tools: - name: run_shell_command yaml_path: ./tool_descriptions/run_shell_command.tool.yaml binding: tools.shell_tools:run_shell_command # No middleware, no skills, no sub_agents ``` Everything below is **available to add** during evolution. ## Validation After any change, **always validate**: ```bash python evolve_agent/skills/nexau-evolution-guide/scripts/validate_agent.py workspace/code_agent.yaml ``` --- ## Adding Tools The agent only starts with `run_shell_command`. Add tools to give the agent more capabilities. ### Available Built-in Tools These tool implementations already exist in `workspace/tools/` and can be registered by adding entries to `code_agent.yaml`: | Tool | Binding | Purpose | |------|---------|---------| | `read_file` | `tools.file_tools:read_file` | Read file with line numbers, offset/limit pagination | | `write_file` | `tools.file_tools:write_file` | Write/overwrite a file | | `replace` | `tools.file_tools:replace` | Find-and-replace in files (exact → flexible → regex fallback) | | `search_file_content` | `tools.file_tools:search_file_content` | Search file contents (ripgrep-style) | | `glob` | `tools.file_tools:glob` | Find files by glob pattern | | `list_directory` | `tools.file_tools:list_directory` | List directory contents | | `run_shell_command` | `tools.shell_tools:run_shell_command` | Execute shell commands (already registered) | | `BackgroundTaskManage` | `tools:background_task_manage_tool` | Manage background processes | | `web_search` | `tools.web_tools:google_web_search` | Google web search | | `web_read` | `tools.web_tools:web_fetch` | Fetch web page content | | `save_memory` | `tools.session_tools:save_memory` | Save notes to memory file | | `write_todos` | `tools.session_tools:write_todos` | Write TODO list | | `complete_task` | `tools.session_tools:complete_task` | Signal task completion (stop tool) | ### How to Register a Tool Add to `tools:` in `workspace/code_agent.yaml`: ```yaml tools: - name: read_file yaml_path: ./tool_descriptions/read_file.tool.yaml binding: tools.file_tools:read_file ``` Each tool needs: 1. **Tool YAML** (`tool_descriptions/*.tool.yaml`) — schema + description for the LLM 2. **Python binding** (`tools/*.py`) — the implementation 3. **Registration** in `code_agent.yaml` under `tools:` If adding `complete_task`, also set `stop_tools: [complete_task]`. ### Creating a New Tool **Step 1 — YAML definition** (`workspace/tool_descriptions/my_tool.tool.yaml`): ```yaml type: tool name: my_tool description: >- What the tool does, when to use it, and any caveats. input_schema: type: object properties: param_name: type: string description: Parameter description required: - param_name additionalProperties: false $schema: http://json-schema.org/draft-07/schema# ``` **Step 2 — Python implementation** (`workspace/tools/my_module.py`): ```python from typing import Any def my_tool(*, param_name: str, agent_state=None) -> dict[str, Any]: # agent_state.get_sandbox() — sandbox for file/shell operations # agent_state.global_storage — GlobalStorage object (NOT a dict, use .get()/.set()) # agent_state.get_global_value(key, default) / .set_global_value(key, value) # Omit agent_state/sandbox from signature if not needed result = f"Processed {param_name}" return { "content": result, # Sent to LLM as tool result "returnDisplay": result, # Shown to user } ``` **Step 3 — Register** in `code_agent.yaml`: ```yaml tools: - name: my_tool yaml_path: ./tool_descriptions/my_tool.tool.yaml binding: tools.my_module:my_tool ``` > **⚠️ CRITICAL**: All three steps required. Missing any one = tool unavailable or agent crashes. ### Tool Modification Ideas | Problem | Action | |---------|--------| | `replace` OLD_STRING_NOT_FOUND | Add fuzzy match with `difflib.get_close_matches` | | Shell output too large | Edit `_truncate_shell_output()` to keep head+tail | | Agent uses `python` not `python3` | Add shim in `run_shell_command.py` | | Tool description unclear | Edit `tool_descriptions/*.tool.yaml` (high-impact, low-risk) | --- ## Adding Middleware The agent starts with **no middleware**. Middleware hooks into the execution pipeline to modify behavior at various points. Register middleware in `code_agent.yaml` under `middlewares:`. Order matters: `before_*` hooks run top-to-bottom; `after_*` hooks run bottom-to-top. ### AgentState & GlobalStorage API Middleware and tools access runtime state via `agent_state`. **`global_storage` is NOT a dict** — it is a thread-safe `GlobalStorage` object. Do NOT use dict methods like `[]`, `setdefault()`, `in`, or `pop()`. **AgentState API:** | Method | Description | |--------|-------------| | `agent_state.get_global_value(key, default)` | Read from global storage | | `agent_state.set_global_value(key, value)` | Write to global storage | | `agent_state.get_context_value(key, default)` | Read from context | | `agent_state.set_context_value(key, value)` | Write to context | | `agent_state.get_sandbox()` | Get sandbox instance | | `agent_state.agent_name` | Agent name (str) | | `agent_state.agent_id` | Agent ID (str) | **GlobalStorage API** (`agent_state.global_storage`): | Method | Description | |--------|-------------| | `.get(key, default=None)` | Read a value | | `.set(key, value)` | Write a value | | `.update(dict)` | Batch write | | `.delete(key)` | Delete a key | | `.keys()` | List all keys | | `.items()` | List all key-value pairs | | `.lock_key(key)` | Context manager for exclusive key access | **Common mistakes:** ```python # ❌ WRONG — GlobalStorage is not a dict storage = agent_state.global_storage storage.setdefault("key", []) # AttributeError storage["key"] = value # TypeError if "key" in storage: # TypeError # ✅ CORRECT storage = agent_state.global_storage val = storage.get("key", []) # Read with default storage.set("key", val) # Write ``` ### Creating Custom Middleware **Step 1 — Create** `workspace/middleware/my_middleware.py`: ```python from nexau.archs.main_sub.execution.hooks import ( Middleware, HookResult, BeforeModelHookInput, AfterModelHookInput, AfterToolHookInput, ModelCallParams, ModelCallFn, ) from nexau.core.messages import Message, Role, TextBlock class MyMiddleware(Middleware): def __init__(self, *, param_a: str = "default"): self.param_a = param_a def before_model(self, hook_input: BeforeModelHookInput) -> HookResult: # hook_input.messages, hook_input.current_iteration, hook_input.max_iterations return HookResult.no_changes() def after_model(self, hook_input: AfterModelHookInput) -> HookResult: # hook_input.parsed_response, hook_input.messages # Can modify: messages, parsed_response, force_continue return HookResult.no_changes() def after_tool(self, hook_input: AfterToolHookInput) -> HookResult: # hook_input.tool_name, hook_input.tool_output, hook_input.sandbox return HookResult.no_changes() def wrap_model_call(self, params: ModelCallParams, call_next: ModelCallFn): # MUST call call_next(params) to proceed return call_next(params) ``` **Step 2 — Register** in `code_agent.yaml`: ```yaml middlewares: - import: middleware.my_middleware:MyMiddleware params: param_a: "value" ``` ### Hook Points Reference | Hook | When | Can modify | Use case | |------|------|-----------|----------| | `before_agent` | Before execution loop | messages | One-time setup | | `after_agent` | After execution loop | — | Cleanup | | `before_model` | Before each LLM call | messages | Inject reminders, compact context | | `after_model` | After LLM response | messages, parsed_response, force_continue | Post-process, force retry | | `before_tool` | Before tool execution | tool inputs | Validate/transform arguments | | `after_tool` | After tool execution | tool_output | Truncate/enrich output | | `wrap_model_call` | Wraps LLM call | params | Error handling, failover | | `wrap_tool_call` | Wraps tool call | params | Timeout, retry | ### Middleware LLM Access Middleware can make its own LLM calls. At runtime, these env vars are always available: | Variable | Value | |----------|-------| | `LLM_API_KEY` | API key for current experiment | | `LLM_BASE_URL` | LLM API endpoint | | `LLM_MODEL` | Model identifier | **In `wrap_model_call`** (preferred — reuse existing client): ```python from nexau.archs.main_sub.execution.llm_caller import LLMCaller class MyLLMMiddleware(Middleware): def wrap_model_call(self, params: ModelCallParams, call_next: ModelCallFn): llm_caller = LLMCaller( params.openai_client, params.llm_config, retry_attempts=1, middleware_manager=None, # None to avoid recursion ) # Make side call, then: return call_next(params) ``` **In other hooks** (create standalone client): ```python import os, openai from nexau.archs.llm.llm_config import LLMConfig client = openai.OpenAI(api_key=os.environ["LLM_API_KEY"], base_url=os.environ["LLM_BASE_URL"]) llm_config = LLMConfig(model=os.environ["LLM_MODEL"], ...) caller = LLMCaller(client, llm_config, retry_attempts=2, middleware_manager=None) ``` > **Always set `middleware_manager=None`** to avoid infinite recursion. --- ## Adding Sub-Agents Sub-agents are child agents with their own prompt, tools, middleware, and isolated context window. ### When to Use | Use sub-agent | Don't use sub-agent | |--------------|-------------------| | Task needs deep, focused context | Simple one-shot operation | | Subtask needs different tools/prompt | Parent's tools are sufficient | | Isolate failure from parent | Overhead not justified | ### Creating a Sub-Agent **Step 1 — Create config** (`workspace/sub_agents/verifier/agent.yaml`): ```yaml type: agent name: verifier max_iterations: 50 max_context_tokens: 128000 system_prompt: ./prompt.md system_prompt_type: jinja tool_call_mode: openai llm_config: model: ${env.LLM_MODEL} base_url: ${env.LLM_BASE_URL} api_key: ${env.LLM_API_KEY} max_tokens: 16000 temperature: 0.3 stream: false api_type: openai_chat_completion tools: - name: run_shell_command yaml_path: ../tool_descriptions/run_shell_command.tool.yaml binding: tools.shell_tools:run_shell_command - name: complete_task
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기