chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
"""List all built-in tools available in Omnigent.
|
||||
|
||||
Returns the live registry of builtin tool names and their
|
||||
descriptions, so the onboarding assistant always recommends
|
||||
from the current set — not a stale hardcoded list.
|
||||
|
||||
Each tool class is imported individually from its own module to
|
||||
avoid importing the ``omnigent.tools.builtins`` package (which
|
||||
transitively pulls in modules that conflict with the ``mcp`` pip
|
||||
package in subprocess environments).
|
||||
"""
|
||||
|
||||
from omnigent_client import tool
|
||||
|
||||
# Maps every builtin tool name to (module_path, class_name).
|
||||
# This is the sole source of truth — when a new builtin is added,
|
||||
# add it here. Each module is imported individually to avoid the
|
||||
# transitive import chain from omnigent.tools.builtins.__init__.
|
||||
_TOOL_CLASSES: dict[str, tuple[str, str]] = {
|
||||
"download_file": ("omnigent.tools.builtins.download_file", "DownloadFileTool"),
|
||||
"export_agent": ("omnigent.tools.builtins.export_agent", "ExportAgentTool"),
|
||||
"hindsight_recall": ("omnigent.tools.builtins.hindsight", "HindsightRecallTool"),
|
||||
"hindsight_reflect": ("omnigent.tools.builtins.hindsight", "HindsightReflectTool"),
|
||||
"hindsight_retain": ("omnigent.tools.builtins.hindsight", "HindsightRetainTool"),
|
||||
"list_files": ("omnigent.tools.builtins.list_files", "ListFilesTool"),
|
||||
"search_conversations": (
|
||||
"omnigent.tools.builtins.search_conversations",
|
||||
"SearchConversationsTool",
|
||||
),
|
||||
"upload_file": ("omnigent.tools.builtins.upload_file", "UploadFileTool"),
|
||||
"web_fetch": ("omnigent.tools.builtins.web_fetch", "WebFetchTool"),
|
||||
"web_search": ("omnigent.tools.builtins.web_search", "WebSearchTool"),
|
||||
}
|
||||
|
||||
|
||||
@tool
|
||||
def list_builtin_tools() -> str:
|
||||
"""
|
||||
List all built-in tools available in Omnigent.
|
||||
|
||||
Returns tool names and descriptions. Call this before
|
||||
recommending tools for a new agent.
|
||||
"""
|
||||
import importlib
|
||||
|
||||
lines: list[str] = []
|
||||
for name in sorted(_TOOL_CLASSES):
|
||||
module_path, class_name = _TOOL_CLASSES[name]
|
||||
module = importlib.import_module(module_path)
|
||||
cls = getattr(module, class_name)
|
||||
lines.append(f"- {name}: {cls.description()}")
|
||||
|
||||
return "\n".join(lines)
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Validate an agent directory's config.yaml.
|
||||
|
||||
Parses and validates the agent spec using the same parser and
|
||||
validator that ``omnigent server`` uses. A passing validation means
|
||||
the agent will load and serve correctly.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from omnigent_client import tool
|
||||
|
||||
from omnigent.errors import OmnigentError
|
||||
|
||||
|
||||
@tool
|
||||
def validate_agent(path: str) -> str:
|
||||
"""
|
||||
Validate an agent directory's config.yaml.
|
||||
|
||||
Returns ``"Valid: <agent-name>"`` if the spec is correct, or
|
||||
a list of errors if something is wrong. Use this after
|
||||
creating an agent to verify it will work.
|
||||
|
||||
:param path: Path to the agent directory containing config.yaml,
|
||||
e.g. ``"/workspace/my-agent"`` or a workspace-relative
|
||||
``"my-agent"``.
|
||||
:returns: A user-facing status string — ``"Valid: <name>..."`` on
|
||||
success, ``"Error: ..."`` or ``"Parse error: ..."`` on
|
||||
failure.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
if not path:
|
||||
return "Error: 'path' parameter is required."
|
||||
|
||||
agent_path = Path(path)
|
||||
# Resolve relative paths against the conversation workspace so
|
||||
# validate_agent("my-agent") works from sandbox mode without the
|
||||
# LLM needing to know the absolute workspace path.
|
||||
if not agent_path.is_absolute():
|
||||
workspace = os.environ.get("_AP_WORKSPACE")
|
||||
if workspace:
|
||||
agent_path = Path(workspace) / agent_path
|
||||
|
||||
if not agent_path.exists():
|
||||
return f"Error: directory '{agent_path}' does not exist."
|
||||
|
||||
config_yaml = agent_path / "config.yaml"
|
||||
if not config_yaml.exists():
|
||||
return f"Error: no config.yaml found in '{agent_path}'."
|
||||
|
||||
try:
|
||||
from omnigent.spec.parser import parse
|
||||
from omnigent.spec.validator import validate
|
||||
|
||||
# expand_env=False: the generated agent may reference env vars
|
||||
# like ${OPENAI_API_KEY} that aren't set in the current process.
|
||||
# These are resolved at deploy/run time, not at creation time.
|
||||
spec = parse(agent_path, expand_env=False)
|
||||
result = validate(spec)
|
||||
|
||||
if result.valid:
|
||||
return f"Valid: agent '{spec.name}' parsed and validated successfully."
|
||||
|
||||
errors = "; ".join(f"{e.path}: {e.message}" for e in result.errors)
|
||||
return f"Validation errors: {errors}"
|
||||
except (OmnigentError, yaml.YAMLError, FileNotFoundError, OSError) as exc:
|
||||
return f"Parse error: {exc}"
|
||||
Reference in New Issue
Block a user