This document is developer-facing notes for uag (a local tool-execution agent).
- Entry points:
- CLI:
python -m uagent(command:uag) - GUI:
python -m uagent.gui(command:uagg) - Web:
python -m uagent.web(command:uagw)
- CLI:
- Python: 3.11+
- Git: required for development workflows and some tools
- OS: Windows / macOS / Linux
Key modules:
- Core state + UI integration:
src/uagent/core.py - CLI UI loop:
src/uagent/cli.py - LLM orchestration entrypoint:
src/uagent/uagent_llm.py- Round/message/tool-call helpers are split into:
src/uagent/llm_helpers.pysrc/uagent/llm_message_helpers.pysrc/uagent/llm_round_helpers.pysrc/uagent/llm_flow_helpers.py
- Retry / backoff helpers live in
src/uagent/llm_errors.py
- Round/message/tool-call helpers are split into:
- Provider wiring (OpenAI/Azure/Gemini/Claude/Vertex AI/Ollama/etc.):
src/uagent/util_providers.py - Common helpers (commands, callbacks injection, messages building, etc.):
src/uagent/util_tools.py - Startup initialization:
src/uagent/runtime_init.py(compatibility re-export)src/uagent/runtime_workdir.py:decide_workdir()/apply_workdir()src/uagent/runtime_banner.py:build_startup_banner()src/uagent/runtime_env.py:validate_or_exit_startup_env(context=...)src/uagent/runtime_memory.py:append_long_memory_system_messages()
runtime_init.pyloads.envand.env.secfrom the current working directory at import time whenpython-dotenvis available (.envfirst, then.env.secdecrypted with.uagent.keyif present)
Documentation:
- Tool development:
src/uagent/docs/DEVELOP_TOOL.md - Host-side i18n:
src/uagent/docs/DEVELOP_I18N.md(compile:python scripts/compile_locales.py, QC:python scripts/po_qc_summary.py)
- Start one of the entry points (
uag/uagg/uagw). - Startup initialization (
runtime_init.py):- Decide workdir (
--workdir/-C,UAGENT_WORKDIR, or current directory) - Create directory if needed and
chdir - Build and print startup banner
- Load
.envand.env.secfrom the current working directory ifpython-dotenvis available
- Decide workdir (
- Tool plugins are loaded from
src/uagent/tools/(and optionally from an external directory). - Provider client is created based on environment variables (
util_providers.make_client). - UI loop (CLI/GUI/Web) receives user input and enqueues events.
- LLM rounds run via
uagent_llm.run_llm_rounds():- If the assistant returns tool calls, tools are executed and results are appended.
- Retry/backoff behavior for rate limits is implemented in
llm_errors.py.
Tools are plugin modules under src/uagent/tools/.
- A module is registered as a tool when it provides:
TOOL_SPEC: dict(OpenAI function schema compatible)run_tool(args: dict) -> str(runner)
Tool loading happens in src/uagent/tools/__init__.py and is triggered at import time.
- Internal tools: discovered by
pkgutil.iter_modules([tools_dir]) - External tools (optional): loaded from
UAGENT_EXTERNAL_TOOLS_DIR(each*.pyfile)
Tools can require host features (Busy status updates, human_ask synchronization, env access).
util_tools.init_tools_callbacks(core) injects callbacks into the tools runtime (tools.init_callbacks).
This is how tools share state with the CLI stdin loop (especially human_ask).
tools.get_tool_specs() returns specs for LLM calls.
Important details:
- Extended fields such as
function.system_promptare removed before sending to the LLM. - For compatibility, the function name may be mirrored to top-level
name.
For GPT-5.4 and later within the GPT-5 line, when Responses API is enabled, uag uses a lighter tool exposure path.
- Target detection is implemented in
uagent_llm._is_gpt54_tool_search_target(...) - A lightweight tools prompt is selected in
util_tools.py - Candidate tool specs are selected by
uagent_llm._select_tool_specs_for_gpt54(...) tool_catalogprovides a lightweight discovery surface before passing full tool definitions- A small safe fallback subset is kept when catalog search returns no hits
This preserves existing behavior for non-target models while reducing payload size for GPT-5.4+ Responses requests.
By default, a one-line trace is printed to stdout before tool execution:
- Example:
[TOOL] 2025-... name=<tool> args=<masked-json> - Secret-like keys are masked.
A tool may suppress the trace using the extended flag:
TOOL_SPEC['function']['x_scheck']['emit_tool_trace'] = False
human_ask uses this to avoid logging the raw user reply.
:skillsinjects the selected skill as a dedicated[SKILL] ...system message.- Skill messages are persisted to the session log and restored on reload.
:skills statusshows active skill messages;:skills clearremoves them.- Keep skill instructions separate from the base
SYSTEM_PROMPT.
Workdir is decided in this priority order:
- CLI option:
--workdir/-C - Environment variable:
UAGENT_WORKDIR - Fallback: current directory
CLI/Web/GUI perform workdir initialization inside main() (not at module import time).
The startup banner (workdir/provider/base_url/api_version/Responses mode, etc.) is generated by:
runtime_init.build_startup_banner()
Long-term memory (personal) and shared memory can be inserted as system messages at startup.
MCP-related tools include:
mcp_servers_tool.pymcp_tools_list_tool.pyhandle_mcp_v2_tool.pymcp_servers_shared.py
Recent smoke tests cover template creation and the basic add/list/validate/set_default/remove flow.
mcp_servers_validate_tool.py is hardened so it can still return raw output when callback-based truncation is unavailable.