What is a uvm agent?

A uvm_agent is a fundamental component of a testbench used for verification of a specific design block or module. The purpose of a uvm_agent is to manage and coordinate various verification components, such as a monitor, driver, sequencer, and possibly other user-defined components, to interact with the design under test (DUT).

Code
// Filename : basic_agent.sv

class basic_agent extends uvm_agent;
    `uvm_component_utils(basic_agent)
    
    basic_driver drvr;
    basic_sequencer seqr;
    basic_monitor mon;
    basic_config cfg;
    
    
    extern         function      new(string name, uvm_component parent);
    extern virtual function void build_phase(uvm_phase phase);
    extern virtual function void connect_phase(uvm_phase phase);
    extern virtual function void end_of_elaboration_phase(uvm_phase phase);
    extern virtual function void start_of_simulation_phase(uvm_phase phase);
    
    extern virtual task  main_phase(uvm_phase phase);
    
    extern virtual function void extract_phase(uvm_phase phase);
    extern virtual function void check_phase(uvm_phase phase);
    extern virtual function void report_phase(uvm_phase phase);
    extern virtual function void final_phase(uvm_phase phase);
    
endclass

//------------------------------------------------------------------//

function basic_agent::new(string name, uvm_component parent);
    super.new(name, parent);

endfunction: new

//------------------------------------------------------------------//

function void basic_agent::build_phase(uvm_phase phase);
    super.build_phase(phase);

    drvr = basic_driver::type_id::create("drvr", this);
    seqr = basic_sequencer::type_id::create("seqr", this);
    mon = basic_monitor::type_id::create("mon", this);
    
endfunction: build_phase

//------------------------------------------------------------------//

function void basic_agent::connect_phase(uvm_phase phase);
    super.connect_phase(phase);

    drvr.seq_item_port.connect(seqr.seq_item_export);
endfunction: connect_phase

//------------------------------------------------------------------//

function void basic_agent::end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    
endfunction: end_of_elaboration_phase

//------------------------------------------------------------------//

function void basic_agent::start_of_simulation_phase(uvm_phase phase);
    super.start_of_simulation_phase(phase);
    
endfunction: start_of_simulation_phase

//------------------------------------------------------------------//

task basic_agent::main_phase(uvm_phase phase);
    super.main_phase(phase);
    phase.raise_objection(this);
    
    phase.drop_objection(this);
endtask: main_phase

//------------------------------------------------------------------//

function void basic_agent::extract_phase(uvm_phase phase);
    super.extract_phase(phase);

endfunction: extract_phase

//------------------------------------------------------------------//

function void basic_agent::check_phase(uvm_phase phase);
    super.check_phase(phase);

endfunction: check_phase

//------------------------------------------------------------------//

function void basic_agent::report_phase(uvm_phase phase);
    super.report_phase(phase);

endfunction: report_phase

//------------------------------------------------------------------//

function void basic_agent::final_phase(uvm_phase phase);
    super.final_phase(phase);

endfunction: final_phase
Theory Questions
    Yes, it is allowed to write code inside the agent. UVM only advises not to write time consuming code in agent, but that is not a hard rule. Depending on iones requirement, the implementation of uvm_agent can be modified.
    Yes, it is advised to use an agent to instantiate various components inside and then use the agent inside the environment . This is done to ensure that the agent acts as a small replacable block where the entire driver , monitor , scoreboard etc is treated as a plug and plag unit.
    UVM agents can be either active , containing a sequencer and driver, or passive , containing only a monitor.
    A UVM agent extends from the uvm_component base class.
    get_is_active()
    A passive UVM agent is preferred when the goal is to monitor signals without driving stimulus, such as for coverage collection or protocol checking.