# Observability Source: https://docs.a1project.org/advanced/observability Debug and monitor agent execution ## Context Tracking View all agent interactions across execution: ```python theme={null} from a1 import get_runtime runtime = get_runtime() # View all contexts for name, ctx in runtime.CTX.items(): print(f"{name}: {len(ctx.messages)} messages") # Get chronological history all_messages = runtime.get_full_context() # Filter by context type main_messages = runtime.get_full_context("main") # User inputs/outputs attempt_messages = runtime.get_full_context("attempt") # Code generation retries intermediate_messages = runtime.get_full_context("intermediate") # LLM calls in code ``` **Context types**: * `main` - Successful user inputs and outputs * `attempt_*` - Code generation attempts and failures * `intermediate_*` - LLM calls from within generated code ## Debugging Failed Attempts See what went wrong during code generation: ```python theme={null} runtime = get_runtime() # View retry attempts for name, ctx in runtime.CTX.items(): if name.startswith("attempt_"): print(f"\n{name}:") for msg in ctx.messages: if "error" in msg.content.lower(): print(f" {msg.content}") ``` ## Logging Enable debug logs to see execution details: ```python theme={null} import logging logging.basicConfig(level=logging.INFO) # See code generation and execution result = await agent.jit(problem="Calculate fibonacci") # Logs show: # - Code generation attempts # - Verification results # - Cost scores # - Selected candidate ``` ## OpenTelemetry A1 integrates with OpenTelemetry for distributed tracing: ```python theme={null} from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter # Setup tracing provider = TracerProvider() processor = BatchSpanProcessor(OTLPSpanExporter()) provider.add_span_processor(processor) trace.set_tracer_provider(provider) # Agent execution automatically traced result = await agent.jit(problem="What is 2+2?") ``` **Trace attributes**: * `agent.name` - Agent identifier * `generation.num_candidates` - Parallel candidates generated * `generation.best_cost` - Selected candidate's cost * `execution.duration` - Total execution time ## Custom Tracing Add custom spans for your operations: ```python theme={null} from opentelemetry import trace tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("custom_operation") as span: span.set_attribute("input.size", len(data)) result = await process(data) span.set_attribute("output.size", len(result)) ``` ## Metrics Track performance metrics: ```python theme={null} from opentelemetry.metrics import get_meter meter = get_meter(__name__) # Counters agent_calls = meter.create_counter("agent.calls") agent_calls.add(1, {"agent": "math_agent"}) # Histograms latency = meter.create_histogram("agent.latency") latency.record(execution_time, {"agent": "math_agent"}) ``` ## Integrations Works with standard observability platforms: * **Jaeger** - Distributed tracing * **Prometheus** - Metrics collection * **DataDog** - APM * **New Relic** - Full-stack observability * **Honeycomb** - Observability platform # Strategies Source: https://docs.a1project.org/advanced/strategies Configure how agents compile to code ## What is a Strategy? Strategy controls how A1 generates and validates code. It has seven components: 1. **RetryStrategy** - Parallel candidates and retries 2. **Generate** - How code is created 3. **Verify** - What validation criteria code must meet 4. **Cost** - How code quality is scored 5. **Compact** - Code optimization (future) 6. **Executor** - Custom execution (future) 7. **Criteria** - LLM-based evaluation (QualitativeCriteria, QuantitativeCriteria) ## RetryStrategy Controls parallel candidates and retry iterations for LLM outputs and code generation. ```python theme={null} from a1 import RetryStrategy, LLM # Default: 3 candidates × 3 retries = up to 9 attempts llm = LLM("gpt-4.1") # Custom retry strategy llm = LLM( "gpt-4.1", retry_strategy=RetryStrategy( max_iterations=5, # Retries per candidate num_candidates=3 # Parallel candidates ) ) ``` **How it works**: 1. Try initial LLM call 2. If validation fails, launch parallel candidates 3. Each candidate retries up to `max_iterations` times 4. First successful candidate wins 5. If all fail, return raw string or raise error ## Strategy Extends RetryStrategy for code generation with verification and cost estimation. ```python theme={null} from a1 import Strategy, Agent strategy = Strategy( max_iterations=3, # Retries per candidate num_candidates=3, # Parallel code candidates verify=my_verify, # Validation function cost=my_cost # Cost estimation function ) agent = Agent( output_schema=int, strategy=strategy ) ``` **Generation pipeline**: ``` 1. GENERATE → num_candidates parallel implementations 2. VERIFY → Filter valid candidates 3. COST → Score each valid candidate 4. SELECT → Pick lowest cost 5. EXECUTE → Run selected code ``` ## Generate Controls how code is created from task descriptions. **Override example**: ```python theme={null} from a1 import BaseGenerate, LLM, Runtime class CustomGenerate(BaseGenerate): def __init__(self): self.llm = LLM("gpt-4.1") async def generate(self, agent, task, return_function=False, past_attempts=None): # Add custom pre-processing task = f"IMPORTANT: {task}" # Call parent implementation definition_code, generated_code = await super().generate( agent, task, return_function, past_attempts ) # Add custom post-processing generated_code = generated_code.replace("print(", "logger.info(") return (definition_code, generated_code) # Use in runtime runtime = Runtime(generate=CustomGenerate()) ``` ## Verify Controls what validation criteria code must meet. **Built-in verifiers**: ```python theme={null} from a1 import IsFunction, IsLoop # Require function definition strategy = Strategy(verify=IsFunction()) # Require loop structure (compiles to agentic while loop) strategy = Strategy(verify=IsLoop()) ``` **Override example**: ```python theme={null} from a1 import BaseVerify, Strategy import ast class RequiresTypeHints(BaseVerify): async def verify(self, code, agent): try: tree = ast.parse(code) except SyntaxError: return (False, "Syntax error") for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): if node.returns is None: return (False, f"Function '{node.name}' missing return type") return (True, None) # Use in strategy strategy = Strategy(verify=RequiresTypeHints()) ``` ## Cost Controls how code quality/efficiency is scored for selection. **Default cost**: Estimates execution cost based on control flow graph (tool calls, loops, branches). **Override example**: ```python theme={null} from a1 import BaseCost, Strategy class LineCountCost(BaseCost): def compute(self, code, agent): lines = [l for l in code.split('\n') if l.strip() and not l.strip().startswith('#')] return float(len(lines)) # Use in strategy strategy = Strategy(cost=LineCountCost()) ``` ## Compact Code optimization strategy (future feature). ```python theme={null} from a1 import BaseCompact class CustomCompact(BaseCompact): def compact(self, code): # Optimize code return optimized_code ``` ## Executor Custom execution environments (future feature). ```python theme={null} from a1 import BaseExecutor class CustomExecutor(BaseExecutor): async def execute(self, code, **kwargs): # Custom execution logic return result ``` ## Criteria LLM-based evaluation for verify and cost functions. ### QualitativeCriteria Boolean (pass/fail) evaluation using natural language. ```python theme={null} from a1 import QualitativeCriteria, LLM, Strategy evaluator = LLM("gpt-4.1") # Single evaluation is_readable = QualitativeCriteria( expression="Code is readable and follows Python best practices", llm=evaluator ) # Multiple samples with voting is_production_ready = QualitativeCriteria( expression="Code is production-ready with proper error handling", llm=evaluator, num_samples=5, # 5 parallel LLM calls min_pass=3 # 3 out of 5 must vote "pass" ) strategy = Strategy(verify=is_production_ready) ``` **Parameters**: * `expression` (str): Natural language criteria * `llm` (Tool): LLM for evaluation * `num_samples` (int): Number of parallel evaluations (default: 1) * `min_pass` (int): Required "pass" votes (default: 1) * `min_samples_for_aggregation` (int): Minimum successful responses (default: 1) ### QuantitativeCriteria Numeric scoring using natural language. ```python theme={null} from a1 import QuantitativeCriteria, LLM, Strategy scorer = LLM("gpt-4.1") # Single score complexity = QuantitativeCriteria( expression="How complex is this code? (0=simple, 10=complex)", llm=scorer, min=0.0, max=10.0 ) # Multiple samples with aggregation avg_complexity = QuantitativeCriteria( expression="Rate complexity (0=simple, 10=complex)", llm=scorer, min=0, max=10, agg="avg", # Aggregation: avg, med, min, max num_samples=5 # 5 parallel scores ) strategy = Strategy(cost=avg_complexity) ``` **Parameters**: * `expression` (str): Natural language scoring criteria * `llm` (Tool): LLM for scoring * `min` (float): Minimum valid score (default: 0.0) * `max` (float): Maximum valid score (default: 10.0) * `agg` (str): Aggregation method - `"avg"`, `"med"`, `"min"`, `"max"` (default: "avg") * `num_samples` (int): Number of parallel scores (default: 1) * `min_samples_for_aggregation` (int): Minimum valid scores needed (default: 1) **Aggregation methods**: * `"avg"` - Mean (balanced estimate) * `"med"` - Median (robust to outliers) * `"min"` - Minimum (conservative) * `"max"` - Maximum (optimistic) ## Complete Example Combining all components: ```python theme={null} from a1 import Strategy, QualitativeCriteria, QuantitativeCriteria, LLM, Agent evaluator = LLM("gpt-4.1") scorer = LLM("gpt-4.1") strategy = Strategy( # Retry configuration max_iterations=3, num_candidates=3, # Verification (must pass) verify=QualitativeCriteria( expression="Code is correct and handles edge cases", llm=evaluator, num_samples=3, min_pass=2 ), # Cost estimation (optimize) cost=QuantitativeCriteria( expression="Rate complexity (0=simple, 10=complex)", llm=scorer, min=0, max=10, agg="avg", num_samples=3 ) ) agent = Agent( output_schema=dict, strategy=strategy ) result = await agent.jit(problem="Parse CSV file") ``` ## Configuration Levels Strategy can be set at multiple levels (higher priority overrides lower): ```python theme={null} from a1 import Runtime, Strategy # 1. Per-call (highest priority) result = await agent.jit(problem="...", strategy=Strategy(num_candidates=10)) # 2. Agent-level agent = Agent(strategy=Strategy(num_candidates=5)) # 3. Runtime-level runtime = Runtime(strategy=Strategy(num_candidates=3)) # 4. Global default (lowest priority) Strategy() # Uses defaults: max_iterations=3, num_candidates=3 ``` # API Reference Source: https://docs.a1project.org/api/reference Complete API reference for A1 ## Agent An agent is defined by its tools, input/output schemas, and description. ```python theme={null} from a1 import Agent from pydantic import BaseModel class Input(BaseModel): query: str class Output(BaseModel): result: str agent = Agent( name="my_agent", description="Does something useful", input_schema=Input, output_schema=Output, tools=[tool1, tool2], skills=[skill1, skill2] ) # Compile ahead-of-time compiled = await agent.aot(cache=True, strategy=None) # Execute just-in-time result = await agent.jit(query="example") ``` **Methods:** * `async aot(cache: bool = True, strategy: Optional[Strategy] = None) -> Tool` - Compile agent to code * `async jit(strategy: Optional[Strategy] = None, **kwargs) -> Any` - Execute immediately ## Tool Tools are callable functions with typed inputs and outputs. ```python theme={null} from a1 import tool @tool async def my_tool(x: int, y: str) -> dict: """Does something useful.""" return {"result": f"{y}: {x}"} # Or create explicitly from a1 import Tool from pydantic import BaseModel class ToolInput(BaseModel): x: int y: str class ToolOutput(BaseModel): result: str tool = Tool( name="my_tool", description="Does something useful", input_schema=ToolInput, output_schema=ToolOutput, execute=lambda x, y: {"result": f"{y}: {x}"}, is_terminal=False ) ``` **Properties:** * `name: str` - Tool identifier * `description: str` - What the tool does * `input_schema: type[BaseModel]` - Pydantic schema for inputs * `output_schema: type[BaseModel]` - Pydantic schema for outputs * `is_terminal: bool` - Whether this ends agent execution ## LLM LLMs are tools that call language models. ```python theme={null} from a1 import LLM llm = LLM( model="gpt-4.1", retry_strategy=None, output_schema=None ) # Use in agent agent = Agent( name="agent", description="Uses LLM", tools=[my_tool, LLM("gpt-4.1-mini")] ) ``` **Parameters:** * `model: str` - Model identifier (e.g., "gpt-4.1", "claude-3-5-sonnet") * `retry_strategy: Optional[RetryStrategy]` - Retry configuration * `output_schema: Optional[type[BaseModel]]` - Structured output schema ## ToolSet Group related tools together. ```python theme={null} from a1 import ToolSet toolset = ToolSet( name="math_tools", description="Mathematical operations", tools=[add, subtract, multiply] ) # Access tools all_tools = toolset.get_all_tools() specific_tool = toolset.get_tool("add") ``` ## Skill Skills provide context or code snippets to agents. ```python theme={null} from a1 import Skill skill = Skill( name="python_basics", description="Python programming fundamentals", content="def example(): ...", modules=["os", "sys"] ) ``` ## SkillSet Group related skills. ```python theme={null} from a1 import SkillSet skillset = SkillSet( name="web_dev", description="Web development skills", skills=[html_skill, css_skill, js_skill] ) ``` ## Strategy Configure code generation and verification. ```python theme={null} from a1 import Strategy strategy = Strategy( max_iterations=3, # Max retry attempts num_candidates=1, # Parallel code candidates generate=None, # Custom code generator verify=None, # Custom verifiers cost=None, # Custom cost function compact=None # Custom compaction ) ``` ## RetryStrategy Configure retry behavior for LLM calls. ```python theme={null} from a1 import RetryStrategy retry = RetryStrategy( max_iterations=3, # Max retry attempts with exponential backoff num_candidates=1 # Number of parallel attempts ) ``` ## Context Manage conversation history. ```python theme={null} from a1 import get_context ctx = get_context("main") ctx.user("What is 2+2?") ctx.assistant("The answer is 4") ctx.tool("calculator", input={"a": 2, "b": 2}, output={"result": 4}) # Access messages messages = ctx.messages ``` **Methods:** * `user(content: str)` - Add user message * `assistant(content: str, tool_calls=None)` - Add assistant message * `tool(name: str, input: Any, output: Any)` - Add tool call result ## RAG Retrieval tools for databases and filesystems. ```python theme={null} from a1 import rag # Database RAG db_tools = rag.database("duckdb://path/to/db.duckdb") # Filesystem RAG fs_tools = rag.filesystem("/path/to/files") # Combined agent = Agent( name="rag_agent", description="Uses RAG", tools=[*db_tools, *fs_tools, LLM("gpt-4.1")] ) ``` ## Runtime (Advanced) Direct access to runtime for advanced use cases. ```python theme={null} from a1 import Runtime, set_runtime runtime = Runtime(cache_dir="./cache") set_runtime(runtime) # Execute tool result = await runtime.execute(tool, **kwargs) # AOT compilation compiled = await runtime.aot(agent, cache=True) # JIT execution result = await runtime.jit(agent, **kwargs) # Context management ctx = runtime.get_full_context(labels=["main", "attempt"]) ``` **Methods:** * `async execute(tool: Tool, **kwargs) -> Any` - Execute a tool * `async aot(agent: Agent, cache: bool = True) -> Tool` - Compile agent * `async jit(agent: Agent, **kwargs) -> Any` - Execute agent JIT * `get_full_context(labels: List[str]) -> Context` - Get merged context ## Verifiers Built-in code verifiers. ```python theme={null} from a1 import IsLoop, IsFunction # Require while loop pattern runtime.verify = [IsLoop()] # Require async function runtime.verify = [IsFunction()] ``` # Installation Source: https://docs.a1project.org/getting-started/installation Install and set up A1 ## Requirements Python 3.12 or higher ## Install ```bash theme={null} pip install a1-compiler ``` Or with uv: ```bash theme={null} uv pip install a1-compiler ``` ## Verify ```python theme={null} import a1 print(f"a1-compiler {a1.__version__} installed!") ``` ## Next Steps * [Quick Start](/getting-started/quick-start) - Build your first agent * [Compilation Guide](/guide/compilation) - Learn AOT vs JIT # Quick Start Source: https://docs.a1project.org/getting-started/quick-start Get up and running with A1 in 5 minutes. ## Your First Agent ```bash theme={null} pip install a1-compiler ``` ```python theme={null} from a1 import Agent, tool, LLM from pydantic import BaseModel # Define a tool @tool(name="add", description="Add two numbers") async def add(a: int, b: int) -> int: return a + b # Define schemas class MathInput(BaseModel): problem: str class MathOutput(BaseModel): answer: int # Create an agent agent = Agent( name="math_agent", description="Solves simple math problems", input_schema=MathInput, output_schema=MathOutput, tools=[add, LLM(model="gpt-4.1")], ) async def main(): # Compile ahead-of-time compiled = await agent.aot( strategy=Strategy( generate=BaseGenerate( llm_tool=LLM(model="gpt-4.1"), ) ) ) result = await compiled.execute(problem="What is 2 + 2?") print(f"AOT result: {result}") # Or execute just-in-time result = await agent.jit(problem="What is 5 + 3?") print(f"JIT result: {result}") import asyncio asyncio.run(main()) ``` ## Key Concepts 1. **Tools** - Functions that agents can call. 2. **Agent** - A composition of tools with input/output schemas. 3. **Compilation** - AOT (ahead-of-time) or JIT (just-in-time) modes. 4. **Schemas** - Pydantic models for type-safe input/output. ## Next Steps * Learn about [Agents](../guide/agents.md) * Explore [Tools](../guide/tools.md) * Understand [Core Concepts](concepts.md) # Agents Source: https://docs.a1project.org/guide/agents Specify what agents can do ## Creating an Agent ```python theme={null} from a1 import Agent, tool, LLM from pydantic import BaseModel @tool async def add(a: int, b: int) -> int: return a + b class MathInput(BaseModel): problem: str class MathOutput(BaseModel): answer: int # Create agent agent = Agent( name="calculator", description="Solves mathematical expressions", input_schema=MathInput, output_schema=MathOutput, tools=[add, multiply, LLM(model="gpt-4.1")], ) ``` ## Running Agents Execute agents with JIT (Just-in-Time): ```python theme={null} result = await agent.jit(problem="What is 2 + 3?") print(result.answer) ``` For AOT compilation to turn agents into reusable tools, see [Compilation](/guide/compilation). ## Agent Properties * **name**: Unique identifier * **description**: What the agent does * **input\_schema**: Pydantic model for inputs * **output\_schema**: Pydantic model for outputs * **tools**: Available tools (Tool, ToolSet, or LLM instances) * **skills**: Optional reusable knowledge ## Accessing Tools ```python theme={null} # Get all tools (flattens ToolSets) all_tools = agent.get_all_tools() # Get specific tool add_tool = agent.get_tool("add") ``` ## Saving and Loading ```python theme={null} # Save to file agent.save_to_file("my_agent.json") # Load from file agent = Agent.load_from_file("my_agent.json") ``` ## Next Steps * Learn about [Tools](/guide/tools) * Explore [Compilation](/guide/compilation) * Use [RAG](/guide/rag) for knowledge # Compilation Source: https://docs.a1project.org/guide/compilation How to run agents in A1 ## Run Agents Execute agents with JIT (Just-in-Time): ```python theme={null} from a1 import Agent, LLM agent = Agent( name="calculator", tools=[LLM("gpt-4.1")] ) # Compile and execute immediately result = await agent.jit(problem="What is 2 + 2?") ``` JIT generates code optimized for each input, then executes it. ## Compile Agents into Tools AOT (Ahead-of-Time) compilation turns agents into reusable tools: ```python theme={null} # Compile once compiled = await agent.aot() # Use many times for i in range(1000): result = await compiled.execute(problem=f"Input {i}") ``` **Caching**: Compiled agents are cached in `.a1/` directory by default. ```python theme={null} # Use cached version if available compiled = await agent.aot(cache=True) # Force recompilation compiled = await agent.aot(cache=False) ``` **Agents as tools**: Compiled agents are tools that can be used in other agents. ```python theme={null} # Compile specialist agent math_agent = Agent(name="math", tools=[LLM("gpt-4.1")]) compiled_math = await math_agent.aot() # Use in another agent coordinator = Agent( name="coordinator", tools=[compiled_math, LLM("gpt-4.1")] ) result = await coordinator.jit(task="Calculate and analyze data") ``` ## How It Works Both AOT and JIT follow this pipeline: ``` 1. Generate → LLM creates code 2. Verify → Check syntax/logic 3. Cost → Rank candidates 4. Execute → Run best code ``` ### Configuration Control code generation with `Strategy`: ```python theme={null} from a1 import Strategy strategy = Strategy( num_candidates=5, # Generate 5 parallel candidates max_iterations=3 # Retry up to 3 times on failure ) compiled = await agent.aot(strategy=strategy) result = await agent.jit(problem="...", strategy=strategy) ``` See [Strategies](../advanced/strategies.md) for detailed configuration. ### Agentic While Loop Use `IsLoop` verifier to compile agents into standard agentic while loops (like LangGraph, AutoGen): ```python theme={null} from a1 import Strategy, IsLoop strategy = Strategy(verify=IsLoop()) # Compiles to while loop structure compiled = await agent.aot(strategy=strategy) ``` This creates an ahead-of-time compiled Python function with a while loop, instead of interpreted runtime execution. ### Performance Tuning **Parallel candidates**: Generate multiple code candidates in parallel and select the best. ```python theme={null} strategy = Strategy(num_candidates=10) result = await agent.jit(problem="...", strategy=strategy) # Generates 10 candidates in parallel, picks lowest cost ``` **Candidate generation** happens in parallel: ``` Candidate 1: [Generate] → [Verify] → [Cost] Candidate 2: [Generate] → [Verify] → [Cost] (parallel) Candidate 3: [Generate] → [Verify] → [Cost] ``` For more advanced configuration (custom verify, cost, generate), see [Strategies](../advanced/strategies.md). # Context Source: https://docs.a1project.org/guide/context Track conversation history and state ## What is Context? Context is a list of messages that tracks conversation history. Each message has a role (`user`, `assistant`, `tool`, `system`) and content. ```python theme={null} from a1 import get_context ctx = get_context("main") # Add messages ctx.user("What is 2+2?") ctx.assistant("4") # Access messages for msg in ctx: print(f"{msg.role}: {msg.content}") ``` ## Messages Four message types: ```python theme={null} # User input ctx.user("Hello") # Assistant response ctx.assistant("Hi there") # Tool calls and results ctx.assistant("", tool_calls=[...]) ctx.tool(content="result", name="tool_name", tool_call_id="id") # System prompts (rare) ctx.system("You are helpful") ``` ## Context Types A1 uses three context types: * **`main`**: Clean successful execution history (user inputs + outputs) * **`attempt_*`**: Code generation/execution attempts (e.g., `attempt_a`, `attempt_b`) * **`intermediate_*`**: LLM calls from within generated code (e.g., `intermediate_a`) ```python theme={null} from a1 import get_runtime runtime = get_runtime() # Access all contexts for name, ctx in runtime.CTX.items(): print(f"{name}: {len(ctx)} messages") ``` ## When Messages Are Added **During JIT execution:** * User input added to `main` at start * Assistant output added to `main` at end * Tool calls added to `main` during execution **During AOT compilation:** * Nothing added to `main` context * Compilation attempts tracked in `attempt_*` contexts * Each candidate gets its own attempt context **During compiled tool execution:** * Same as regular tool execution * Nothing added to `main` context (it's just a tool) ## Runtime Runtime manages all contexts for a session: ```python theme={null} from a1 import Runtime runtime = Runtime() with runtime: ctx = get_context("main") ctx.user("Hello") ``` Runtime handles: * Context lifecycle (creation, cleanup) * Named contexts (`main`, `attempt_a`, `intermediate_a`, etc.) * Context isolation between sessions ## Persistence Save and load contexts and runtime state: ```python theme={null} from a1 import Context, Runtime # Auto-save context on every change ctx = Context.from_file("chat.json", keep_updated=True) ctx.user("Hello") # Automatically saved # Load context ctx = Context.from_file("chat.json") # Auto-save entire runtime and all contexts runtime = Runtime.from_file("session.json", keep_updated=True) with runtime: ctx = get_context("main") ctx.user("Hello") # All contexts auto-saved to session.json # Load runtime with all contexts restored runtime = Runtime.from_file("session.json") ``` # Skills Source: https://docs.a1project.org/guide/skills Give your agent know-how ## Creating Skills ### Manual Creation ```python theme={null} from a1 import Skill skill = Skill( name="web_research", description="Research methodology", content=""" 1. Search broadly 2. Extract key information 3. Cross-reference sources """, modules=["requests"] ) ``` ### From URLs Create skills automatically from web documentation, articles, or tutorials: ```python theme={null} from a1 import Skill skill = await Skill.from_url( urls="https://docs.a1project.org/", name="a1", description="The agent-to-code compiler" ) ``` Requires `pip install crawl4ai`. The method crawls the URLs, uses an LLM to summarize the content into a skill, and auto-detects Python modules mentioned in the content. ## Using Skills ```python theme={null} agent = Agent( name="researcher", description="Researches topics", skills=[skill], tools=[search_tool, LLM("gpt-4.1")] ) ``` ## SkillSets Group related skills: ```python theme={null} from a1 import SkillSet, Skill research_skills = SkillSet( name="research", description="All research-related skills", skills=[ web_research_skill, academic_research_skill, data_analysis_skill, ] ) ``` ## Using Skills with Agents ```python theme={null} from a1 import Agent, Skill, LLM researcher_skill = Skill( name="researcher", description="Research methodology", content="...", modules=[] ) agent = Agent( name="research_agent", skills=[researcher_skill], tools=[LLM(model="gpt-4.1")], ) ``` ## Best Practices ### Document Clearly Good skills have clear, actionable content: ```python theme={null} skill = Skill( name="summarization", description="How to write good summaries", content=""" Key points for effective summaries: - Identify main ideas (typically 3-5) - Use bullet points - Include specific numbers/facts - Preserve original meaning - Keep to 1/3 original length """, modules=[] ) ``` ### Organize Hierarchically Use SkillSets to organize complex skill collections: ```python theme={null} writing_skills = SkillSet( name="writing", skills=[ Skill(name="storytelling", description="..."), Skill(name="technical_writing", description="..."), Skill(name="summarization", description="..."), ] ) ``` ### Include Required Modules Specify Python modules the skill needs: ```python theme={null} data_skill = Skill( name="data_analysis", description="...", content="...", modules=["pandas", "numpy", "scipy"] ) ``` ## Next Steps * Learn about [Agents](agents.md) * Create [Tools](tools.md) # Tools Source: https://docs.a1project.org/guide/tools Create tools for agents to take action ## Python Functions Create tools from any async function using the `@tool` decorator: ```python theme={null} from a1 import tool @tool async def search(query: str) -> list[str]: """Search the web.""" return results @tool async def calculate(expression: str) -> float: """Evaluate math expression.""" return eval(expression) ``` Or pass functions directly to Agent (auto-converted to tools): ```python theme={null} async def divide(a: float, b: float) -> float: """Divide two numbers.""" return a / b agent = Agent(tools=[search, divide]) # Both @tool and raw functions work ``` Supports primitive and complex return types (Pydantic models, lists, dicts). ## Descriptions Add descriptions to help LLMs understand tools: ```python theme={null} @tool( name="api_call", description="Make an HTTP request to an endpoint" ) async def api_call(url: str, method: str = "GET") -> str: ... ``` **Note**: The `name` parameter sets the tool name (defaults to the function name), and the `description` parameter sets the tool description (defaults to the function's docstring). ## OpenAPI Create tools from OpenAPI 3.0 specifications: ```python theme={null} from a1 import ToolSet tools = await ToolSet.from_openapi("https://api.example.com") ``` Auto-detects spec at `/openapi.json`, `/openapi.yaml`, `/swagger.json`, or `/swagger.yaml`. ## Model Context Protocol (MCP) Create tools from MCP servers: ```python theme={null} from a1 import ToolSet config = { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"] } } } tools = await ToolSet.from_mcp_servers(config) ``` ## LLM LLMs are tools that call language models with structured output and retry logic: ```python theme={null} from a1 import LLM, RetryStrategy from pydantic import BaseModel class Answer(BaseModel): result: float explanation: str # Basic LLM tool llm = LLM("gpt-4.1") # With structured output llm = LLM( model="gpt-4.1", output_schema=Answer ) # Custom retry strategy (default: 3 candidates × 3 retries) llm = LLM( model="gpt-4.1", retry_strategy=RetryStrategy(max_iterations=5, num_candidates=2) ) ``` **Supported providers**: OpenAI, Anthropic, Google, Groq (via `groq:model-name`) Use LLM tools like any other tool in agents. ## EM EMs are tools that call embedding models for semantic similarity. The use-case for this is classification. If any enum in your agent/tool schemas (input/output) has >100 values, the compiler translates all relevant LLM calls into a fused EM-LLM pipeline that first filters to semantically relevant enum options and then invokes the LLM with its output constrained to be one of the filtered options. A1 statically detects enums that are too large and will require an EM tool if detected. A1 transparently owns adaptive rate limit handling, chunk-parallelism, and caching vectors within the current Runtime. Semantic classification example: ```python theme={null} from enum import Enum from pydantic import BaseModel, Field # Large enum (1M values) Category = Enum('Category', {f'CAT_{i}': f'cat_{i}' for i in range(1_000_000)}) class Output(BaseModel): category: Category agent = Agent( output_schema=Output, tools=[EM("text-embedding-3-small"), LLM("gpt-4.1")] # EM required ) ``` ## RAG RAG provides readonly or full access to databases and filesystems: ```python theme={null} from a1 import RAG, Database, FileSystem # Readonly database access (SELECT only) rag = RAG(database="sqlite:///data.db") # Readonly filesystem access (ls, grep, cat) rag = RAG(filesystem="/path/to/files") agent = Agent( name="safe_agent", tools=[rag.get_toolset(), LLM("gpt-4.1")] ) ``` **Readonly tools**: `sql` (SELECT), `ls` (list), `grep` (search), `cat` (read) For full read/write access, use `Database` or `FileSystem` directly: ```python theme={null} # Full database access (SELECT, INSERT, UPDATE, DELETE) db = Database("postgresql://user:pass@host/db") # Full filesystem access (ls, grep, cat, write_file, delete_file) fs = FileSystem("s3://bucket/path") agent = Agent( tools=[db.get_toolset(), fs.get_toolset(), LLM("gpt-4.1")] ) ``` **Supported databases**: PostgreSQL, MySQL, SQLite, DuckDB, SQL Server, Oracle **Supported paths**: Local filesystems, S3, Google Cloud Storage, Azure Blob Storage ## ToolSet Group related tools together to organize hierarchically: ```python theme={null} from a1 import ToolSet math_tools = ToolSet( name="math", description="Mathematical operations", tools=[add, multiply, divide] ) agent = Agent( tools=[math_tools, LLM("gpt-4.1")] ) ``` ## Done Built-in `is_terminal=True` tool for marking workflow completion: ```python theme={null} from a1 import Done done = Done() # Agent can call this to signal completion ```