SimLab is agent-agnostic. The default reference agent uses a tool-calling loop with any LLM API (via LiteLLM), but you can bring your own agent by implementing the BaseAgent contract. Install via:
Your agent extends BaseAgent and implements four methods:
from simlab.agents import BaseAgent, BaseEnvironment, RunArtifacts, ToolCallclass MyAgent(BaseAgent): @staticmethod def name() -> str: return "my-agent" def version(self) -> str | None: return "1.0.0" def setup(self, environment: BaseEnvironment) -> None: """Called once before run(). Use to discover tools, warm up models, etc.""" self.tools = environment.list_tools() def run( self, instruction: str, environment: BaseEnvironment, context: RunArtifacts, ) -> None: """Execute the task using a think-act-observe loop.""" # 1. Send the instruction to your LLM along with available tools messages = [{"role": "user", "content": instruction}] context.record_message("user", instruction) max_steps = context.max_steps or 20 for step in range(max_steps): # 2. Think — ask your LLM to decide the next action llm_response = self.call_llm(messages, tools=self.tools) if llm_response.is_done: # LLM decided the task is complete context.set_final_observation(llm_response.text) break # 3. Act — execute the tool call the LLM chose tool_call = ToolCall( tool_server=llm_response.tool_server, tool_name=llm_response.tool_name, parameters=llm_response.parameters, ) result = environment.call_tool( tool_call.tool_server, tool_call.tool_name, tool_call.parameters, ) # 4. Observe — record the result and feed it back to the LLM context.record_tool_call(tool_call, result) messages.append({"role": "assistant", "content": f"Called {tool_call.tool_name}"}) messages.append({"role": "tool", "content": str(result.observation)})
self.call_llm() is your own LLM integration — use any provider (OpenAI, Anthropic, etc.). SimLab is model-agnostic.