UNPKG

simullm

Version:

Event-driven Agent-Based Modeling framework for TypeScript

246 lines (188 loc) 6.62 kB
# simullm Event-driven Agent-Based Modeling framework for TypeScript. ## Features - **Event-driven architecture**: Agents respond to actions/messages in a reactive system - **Type-safe**: Full TypeScript support with generic types for state and actions - **Flexible state management**: Both global state and agent internal state - **Exit conditions**: Required termination logic prevents infinite loops - **Async support**: Handles both synchronous and asynchronous agent actions - **Action cascading**: Agents can dispatch new actions during processing - **Memory management**: Agents can maintain internal state across turns ## Installation ```bash npm install simullm # or bun add simullm ``` ## Quick Start ```typescript import { createSimulation, createAgent } from 'simullm'; // Define your state and action types interface CounterState { value: number; } type CounterAction = | { type: "INCREMENT"; amount: number } | { type: "RESET" }; // Create agents const counterAgent = createAgent<CounterState, CounterAction>( "counter", (action, context) => { if (action.type === "INCREMENT") { context.updateGlobalState(state => ({ value: state.value + action.amount })); } else if (action.type === "RESET") { context.updateGlobalState(state => ({ value: 0 })); } } ); // Create simulation with required exit condition const simulation = createSimulation<CounterState, CounterAction>({ initialGlobalState: { value: 0 }, agents: [counterAgent], shouldExit: ({ actionCount, globalState }) => actionCount >= 10 || globalState.value >= 100 }); // Run simulation await simulation.dispatch({ type: "INCREMENT", amount: 5 }); await simulation.dispatch({ type: "INCREMENT", amount: 15 }); console.log(simulation.getGlobalState()); // { value: 20 } console.log(simulation.getActionCount()); // 2 ``` ## Core Concepts ### Agents Agents are reactive entities that respond to actions. They can: - Update global state - Update their own internal state - Dispatch new actions - Maintain memory across turns - Coordinate with other agents via `context.allAgents` ### Actions Actions are messages passed through the system. All agents receive every action and can choose to respond. ### Exit Conditions (Required) Every simulation must define when to stop via the `shouldExit` function. You have access to: - `globalState`: Current global state - `agentStates`: All agent internal states - `lastAction`: The action that was just processed - `actionCount`: Total number of processed actions ## Examples ### Basic Counter ```typescript const simulation = createSimulation({ initialGlobalState: { value: 0 }, agents: [counterAgent], shouldExit: ({ actionCount }) => actionCount >= 5 }); ``` ### State-based Exit ```typescript const simulation = createSimulation({ initialGlobalState: { temperature: 20 }, agents: [heatingAgent, coolingAgent], shouldExit: ({ globalState }) => globalState.temperature >= 100 || globalState.temperature <= 0 }); ``` ### Agent Memory Exit ```typescript const simulation = createSimulation({ initialGlobalState: { score: 0 }, agents: [learningAgent], shouldExit: ({ agentStates }) => agentStates["learner"]?.experience >= 1000 }); ``` ## API Reference ### `createSimulation<TGlobalState, TAction>(config)` Creates a new simulation instance. **Config:** - `initialGlobalState: TGlobalState` - Starting global state - `agents: Agent[]` - Array of agents to participate - `shouldExit: (context: ExitContext) => boolean` - **Required** exit condition **Returns:** `EventSimulation<TGlobalState, TAction>` ### `createAgent<TGlobalState, TAction, TInternalState>(id, onAction, initialInternalState?)` Creates a new agent. **Parameters:** - `id: string` - Unique agent identifier - `onAction: (action, context) => void | Promise<void>` - Action handler - `initialInternalState?: TInternalState` - Optional internal state ### `EventSimulation` Methods - `dispatch(action)` - Dispatch an action to all agents - `exit()` - Returns a promise that resolves when simulation exits - `getGlobalState()` - Get current global state - `getAgentInternalState(agentId)` - Get agent's internal state - `getAllAgentStates()` - Get all agent internal states - `getActionCount()` - Get total processed actions - `hasSimulationExited()` - Check if simulation has terminated ## Advanced Usage ### Agent Context Properties Each agent receives a context object with: - `globalState` - Current global state (read-only) - `internalState` - Agent's private state (read-only) - `allAgents` - Array of all agents with their IDs and internal states - `dispatch(action)` - Dispatch new actions - `updateGlobalState(updater)` - Modify global state - `updateInternalState(updater)` - Modify agent's internal state ### Agent Coordination Use `context.allAgents` to coordinate between agents: ```typescript const coordinator = createAgent("coordinator", (action, context) => { // Find available workers const availableWorkers = context.allAgents .filter(agent => agent.id !== "coordinator" && !agent.internalState?.busy) .map(agent => agent.id); // Assign tasks to available workers availableWorkers.forEach(workerId => { context.dispatch({ type: "ASSIGN_TASK", agentId: workerId }); }); }); ``` ### Waiting for Simulation Completion Use the `exit()` method to wait for simulations to complete: ```typescript // Start simulation simulation.dispatch({ type: "START" }); // Wait for completion await simulation.exit(); console.log("Simulation completed!"); console.log("Final state:", simulation.getGlobalState()); ``` ### Examples See the `/experiments` directory for complete examples: - Counter simulation with turn-based agents - Predator-prey ecosystem simulation - Market trading simulation with LLM agents ## Migration from v0.1.x **Breaking Change:** The `shouldExit` property is now required in `SimulationConfig`. **Before (v0.1.x):** ```typescript const simulation = createSimulation({ initialGlobalState: { value: 0 }, agents: [myAgent] // Could run infinitely }); ``` **After (v0.2.x):** ```typescript const simulation = createSimulation({ initialGlobalState: { value: 0 }, agents: [myAgent], shouldExit: ({ actionCount }) => actionCount >= 10 // Required }); ``` ## Development ### Release Process Use the automated release script: ```bash bun run release ``` This handles: - Version bumping (patch/minor/major) - Changelog updates - Git commit and tagging - Pushing to remote - npm publishing See `scripts/README.md` for details. ## License MIT