simbiot-harness/venv/lib/python3.12/site-packages/strands/experimental/agent_config.py
Simbiot Harness b60439152b Simbiot Harness v0.1: тактовая лестница на Strands + CQRS/ES-спина
- harness/es.py: append-only event store + проекции (образец — кооп-портал)
- harness/levels.py: уровни 1с/1м/1ч/1д, контекст ∝ масштабу
- harness/scheduler.py: уровневые потоки, идемпотентные тики, absorbed-стабы
- harness/isolated_runner.py + _llm_worker.py: LLM-тик в сабпроцессе
  (глобальный asyncio-рантайм Strands не переживает 2+ create_harness)
- cli.py: init/task/tasks/status/events + requeue (написан самим минутным агентом)
- 9router: отдельный ключ sk-simbiot, модель auto (glm-5.3 первым)
2026-09-29 15:28:50 +00:00

139 lines
5 KiB
Python

"""Experimental agent configuration utilities.
This module provides utilities for creating agents from configuration files or dictionaries.
Note: Configuration-based agent setup only works for tools that don't require code-based
instantiation. For tools that need constructor arguments or complex setup, use the
programmatic approach after creating the agent:
agent = config_to_agent("config.json")
# Add tools that need code-based instantiation
agent.tool_registry.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
"""
import json
from pathlib import Path
from typing import Any
import jsonschema
from jsonschema import ValidationError
# JSON Schema for agent configuration
AGENT_CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Agent Configuration",
"description": "Configuration schema for creating agents",
"type": "object",
"properties": {
"name": {"description": "Name of the agent", "type": ["string", "null"], "default": None},
"model": {
"description": "The model ID to use for this agent. If not specified, uses the default model.",
"type": ["string", "null"],
"default": None,
},
"prompt": {
"description": "The system prompt for the agent. Provides high level context to the agent.",
"type": ["string", "null"],
"default": None,
},
"tools": {
"description": "List of tools the agent can use. Can be file paths, "
"Python module names, or @tool annotated functions in files.",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
"additionalProperties": False,
}
# Pre-compile validator for better performance
_VALIDATOR = jsonschema.Draft7Validator(AGENT_CONFIG_SCHEMA)
def config_to_agent(config: str | dict[str, Any], **kwargs: dict[str, Any]) -> Any:
"""Create an Agent from a configuration file or dictionary.
This function supports tools that can be loaded declaratively (file paths, module names,
or @tool annotated functions). For tools requiring code-based instantiation with constructor
arguments, add them programmatically after creating the agent:
agent = config_to_agent("config.json")
agent.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
Args:
config: Either a file path (with optional file:// prefix) or a configuration dictionary
**kwargs: Additional keyword arguments to pass to the Agent constructor
Returns:
Agent: A configured Agent instance
Raises:
FileNotFoundError: If the configuration file doesn't exist
json.JSONDecodeError: If the configuration file contains invalid JSON
ValueError: If the configuration is invalid or tools cannot be loaded
Examples:
Create agent from file:
>>> agent = config_to_agent("/path/to/config.json")
Create agent from file with file:// prefix:
>>> agent = config_to_agent("file:///path/to/config.json")
Create agent from dictionary:
>>> config = {"model": "anthropic.claude-3-5-sonnet-20241022-v2:0", "tools": ["calculator"]}
>>> agent = config_to_agent(config)
"""
# Parse configuration
if isinstance(config, str):
# Handle file path
file_path = config
# Remove file:// prefix if present
if file_path.startswith("file://"):
file_path = file_path[7:]
# Load JSON from file
config_path = Path(file_path)
if not config_path.exists():
raise FileNotFoundError(f"Configuration file not found: {file_path}")
with open(config_path) as f:
config_dict = json.load(f)
elif isinstance(config, dict):
config_dict = config.copy()
else:
raise ValueError("Config must be a file path string or dictionary")
# Validate configuration against schema
try:
_VALIDATOR.validate(config_dict)
except ValidationError as e:
# Provide more detailed error message
error_path = " -> ".join(str(p) for p in e.absolute_path) if e.absolute_path else "root"
raise ValueError(f"Configuration validation error at {error_path}: {e.message}") from e
# Prepare Agent constructor arguments
agent_kwargs = {}
# Map configuration keys to Agent constructor parameters
config_mapping = {
"model": "model",
"prompt": "system_prompt",
"tools": "tools",
"name": "name",
}
# Only include non-None values from config
for config_key, agent_param in config_mapping.items():
if config_key in config_dict and config_dict[config_key] is not None:
agent_kwargs[agent_param] = config_dict[config_key]
# Override with any additional kwargs provided
agent_kwargs.update(kwargs)
# Import Agent at runtime to avoid circular imports
from ..agent import Agent
# Create and return Agent
return Agent(**agent_kwargs)