Tools

Utility tools available from the primfunctions package that you can use anywhere in your agent code.


Logger#

primfunctions.logger lets you log messages from anywhere in your agent code without needing to yield a LogEvent back to the handler.

from primfunctions.logger import logger

Methods#

All methods accept a message string and an optional attributes dictionary for additional context.

logger.info("Lead qualified", {"lead_id": "abc123"}) logger.warn("Retrying API call", {"attempt": 2}) logger.error("Payment failed", {"order_id": "456"}) logger.debug("Entering fallback branch")
MethodDescription
logger.info(message, attributes=None)General information
logger.warn(message, attributes=None)Warnings
logger.error(message, attributes=None)Errors
logger.debug(message, attributes=None)Debug details

Where Logs Appear#

  • Events tab — Each call emits a LogEvent that appears in the session details Events tab with the log level, message, and the source file and line number where it was called.
  • Traces tab — If tracing is enabled, each log entry also creates a span in the Traces tab.

Example#

from primfunctions.events import Event, StartEvent, TextEvent, TextToSpeechEvent from primfunctions.context import Context from primfunctions.logger import logger async def handler(event: Event, context: Context): if isinstance(event, StartEvent): logger.info("Session started") yield TextToSpeechEvent(text="Hello!") if isinstance(event, TextEvent): user_message = event.data.get("text", "N/A") logger.info("Received user message", {"text": user_message}) result = await process_message(user_message) if result.get("error"): logger.error("Processing failed", {"error": result["error"]}) else: logger.debug("Processing succeeded", {"tokens": result["token_count"]}) yield TextToSpeechEvent(text=result["reply"])

Local Development#

When running locally outside the sandbox, the logger falls back to printing to the console:

[info] Session started
[error] Processing failed

Tracer#

primfunctions.tracer provides a decorator you can apply to any Python function to trace its inputs and outputs. If tracing is not enabled, the decorator is a no-op.

from primfunctions.tracer import tracer

@tracer.tool#

Decorate a function to trace its execution. Works with both sync and async functions.

@tracer.tool def fetch_user(user_id: str) -> dict: # inputs and outputs are captured automatically return db.get_user(user_id) @tracer.tool async def search_products(query: str) -> list: return await catalog.search(query)

You can optionally pass name, description, and parameters for richer trace metadata:

@tracer.tool(name="lookup_order", description="Look up an order by ID") async def lookup_order(order_id: str) -> dict: return await orders.get(order_id)

Where Traces Appear#

Traced function calls appear as spans in the Traces tab of the session details page, showing the function name, inputs, outputs, and duration.

Example#

from primfunctions.events import Event, StartEvent, TextToSpeechEvent from primfunctions.context import Context from primfunctions.logger import logger from primfunctions.tracer import tracer @tracer.tool async def get_account_balance(account_id: str) -> dict: logger.info("Fetching balance", {"account_id": account_id}) balance = await accounts_api.get_balance(account_id) return {"account_id": account_id, "balance": balance} async def handler(event: Event, context: Context): if isinstance(event, StartEvent): account_id = context.data.get("account_id") result = await get_account_balance(account_id) yield TextToSpeechEvent(text=f"Your balance is ${result['balance']}")

Local Development#

When tracing is not enabled, @tracer.tool has no effect — the decorated function runs exactly as if the decorator were not present.

loggertracerobservabilitydebugging