Sessions & Debugging — Agentuity Documentation

Sessions & Debugging

Debug agents using session IDs, CLI commands, and trace timelines

Every request to your agents gets a unique session ID (sess_...). Sessions link logs, traces, and state, making them essential for debugging.

Why Sessions?

Traditional observability tracks individual HTTP requests. That works for stateless web servers. Agents go beyond single requests: a conversation might span dozens of LLM calls, tool executions, and orchestration steps across multiple interactions.

Without sessions, debugging becomes guesswork. You see individual logs but can't connect them. Was that error from the same conversation? What happened before it failed? Which user was affected?

Agentuity tracks runs as sessions and groups related sessions into threads. That gives you a shared ID to connect logs, spans, thread state, and request-scoped session state.

In practice:

  • Unified tracing: All logs, spans, and state from a single request are linked by session ID
  • Conversation context: Sessions group into threads, so you can trace multi-turn conversations
  • Automatic correlation: No manual tracking code, every call in a session is connected
  • Session inspection: Review what happened in a session to reproduce issues

Sessions vs Threads

ScopeLifetimeID PrefixUse For
SessionSingle requestsess_Debugging, request-scoped state
ThreadUp to 1 hour of inactivitythrd_Chat history, user preferences

A thread contains multiple sessions. When a user has a multi-turn conversation, each message creates a new session within the same thread.

Accessing Session ID

import { createAgent } from '@agentuity/runtime';
 
const agent = createAgent('SessionExample', {
  handler: async (ctx, input) => {
    // In agents
    ctx.logger.child({ sessionId: ctx.sessionId }).info('Processing request');
 
    // Thread ID for conversation tracking
    ctx.logger.child({ threadId: ctx.thread.id }).info('Thread context');
 
    return { sessionId: ctx.sessionId };
  },
});

In routes:

import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
import myAgent from '@agent/my-agent/agent';
 
const router = new Hono<Env>();
 
router.post('/', myAgent.validator(), async (c) => {
  const input = c.req.valid('json');
 
  // In routes
  c.var.logger.child({ sessionId: c.var.sessionId }).info('Route called');
 
  const result = await myAgent.run(input);
 
  return c.json({ ...result, sessionId: c.var.sessionId });
});
 
export default router;

Viewing Session Logs

Use the CLI to view logs for a specific session:

agentuity cloud session logs sess_abc123xyz

See Session Logs for additional session commands.

Including Session ID in Responses

For easier debugging, include the session ID in error responses:

const agent = createAgent('ErrorHandler', {
  handler: async (ctx, input) => {
    try {
      const result = await processRequest(input);
      return { success: true, data: result };
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      ctx.logger.child({
        sessionId: ctx.sessionId,
        error: message,
      }).error('Request failed');
 
      return {
        success: false,
        error: 'Processing failed',
        sessionId: ctx.sessionId, // Helpful for debugging
      };
    }
  },
});

Linking External Logs

If you use external logging services, include the session ID so you can connect logs across systems:

const agent = createAgent('WebhookHandler', {
  handler: async (ctx, input) => {
    // Create a logger with session context for external services
    const requestLogger = ctx.logger.child({
      sessionId: ctx.sessionId,
      threadId: ctx.thread.id,
      service: 'webhook-handler',
    });
 
    requestLogger.info('Processing webhook', { eventType: input.event });
 
    // External service call with session context
    await externalApi.process({
      ...input,
      metadata: { agentuitySessionId: ctx.sessionId },
    });
 
    return { success: true };
  },
});

Session State

Use session state for request-scoped data that doesn't persist:

const agent = createAgent('TimingExample', {
  handler: async (ctx, input) => {
    // Track timing within this request
    ctx.session.state.set('startTime', Date.now());
 
    const result = await processRequest(input);
 
    const startTime = ctx.session.state.get('startTime');
    const duration = typeof startTime === 'number' ? Date.now() - startTime : 0;
    ctx.logger.child({ durationMs: duration }).info('Request completed');
 
    return result;
  },
});

Session state is cleared after the response. For persistent data, use thread state or KV storage.

Metadata

Store unencrypted metadata for filtering and querying. Keep metadata limited to non-sensitive values or opaque internal identifiers. Do not store secrets, tokens, raw emails, names, or other sensitive personal data. Use session metadata for values tied to one request. Use thread metadata for values that should stay with the conversation.

import { createAgent } from '@agentuity/runtime';
 
const agent = createAgent('UserContext', {
  handler: async (ctx, input) => {
    ctx.session.metadata.requestType = input.requestType;
 
    const threadMetadata = {
      ...(await ctx.thread.getMetadata()), // keep existing keys
      userId: input.userId,
      department: 'sales',
      plan: input.plan,
    };
 
    await ctx.thread.setMetadata(threadMetadata);
 
    ctx.logger.child({
      threadId: ctx.thread.id,
      sessionId: ctx.sessionId,
      userId: threadMetadata.userId,
      requestType: input.requestType,
    }).info('Request context');
 
    return { success: true };
  },
});
 
export default agent;

Metadata vs State

AspectMetadataState
StorageUnencrypted, indexedSerialized user data
Use caseFiltering, querying, analyticsConversation or request data
Accessctx.session.metadata or await ctx.thread.getMetadata() / await ctx.thread.setMetadata(...)ctx.session.state / ctx.thread.state
Best forUser IDs, request types, account plansMessages, preferences, temporary request values

Best Practices

  • Include session ID in logs and error responses: Makes it easy to trace issues back to specific requests
  • Use logging context: Add searchable fields to logs for easier filtering
  • Create child loggers: Add session context to component-specific loggers

Next Steps