Is there any way to track on an agent session if t...
# ask-ai
a
Is there any way to track on an agent session if the agent is in a tool context or not?
t
Thanks for reaching out, Ahron. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding to your question about tracking whether an agent is currently in a tool context during an agent session. Yes — you can detect and track when an agent is operating inside a tool context. Here are practical ways to do that using the session and run context objects: • Use the RunContext passed into tools ◦ The
RunContext
is provided to function tools and contains the state for the current tool invocation (session, agent, and related metadata). ◦ When a tool is invoked, presence of a
RunContext.function_call
(or related fields on the
RunContext
) signals that a tool execution is active. • Inspect run-level handles and interruption flags ◦
run_ctx.speech_handle.interrupted
can be checked to detect interruptions to tool execution — this is useful for determining whether a running tool was interrupted. ◦ Long-running tools commonly expose asyncio tasks or cancellation tokens via the run context; checking whether those tasks are active indicates an ongoing tool run. • Observe agent session events ◦ Agent sessions emit events such as
conversation_item_added
when a function tool is called or when the tool returns output. Listening for these events externally lets you monitor when tools start and finish. ◦ You can track a simple state machine: on function-call event → mark agent in tool context; on function-complete/output event → mark agent out of tool context. • Combine approaches for robustness ◦ For short-lived tools, using
RunContext.function_call
plus the session events is usually sufficient. ◦ For long-running tools, track the asyncio task or cancellation token exposed in the run context and update the session state when that task completes or is cancelled. If you’d like, tell me which environment you’re using (server-side Python/Node, or an SDK) and whether tools you care about are short-lived or long-running — I can give a short code sketch showing where to check
run_ctx
and how to subscribe to the
conversation_item_added
events. Sources: Tool definition and use | LiveKit Documentation | Agent session | LiveKit Documentation
a
I want to keep track from outside the tools to handle different things based on the context
t
Thanks — I’m replying about tracking tool context from outside the tools so you can run different logic depending on whether an agent is inside a tool. This is doable. A reliable approach is to subscribe to the agent session events and maintain a small external state machine that marks the agent as "in tool" or "out of tool." Before I give a concrete pattern, a couple quick clarifying questions so I can tailor the example to your setup: • Which environment/SDK are you using to run and observe agent sessions (server-side Python, Node, or another platform)? • Are the tools you need to track typically short-lived (return quickly) or long-running (separate async tasks, cancellable)? • Do you prefer an event-driven approach (listen to session events) or polling the session/run state periodically? If you want a quick sketch now, here’s a general pattern you can implement in any environment: 1. Subscribe to agent session events ◦ Listen for events like
conversation_item_added
(emitted when a function call starts or a function output is added). ◦ Also listen for events indicating function completion, cancellation, or errors. 1. Maintain an external state for each agent session ◦ When you detect a function-call start event, set session_state[session_id] = "in_tool" and record metadata (tool name, run id, start timestamp). ◦ When you detect a function completion/cancel/output event for that run id, set session_state[session_id] = "out_of_tool" and clear metadata. 1. Correlate events to runs ◦ Use identifiers available on the event (function call id, run id, or conversation item id) to ensure you only flip state when the matching run completes. This avoids race conditions when multiple tools are invoked. 1. Handle long-running tools ◦ If tools spawn async tasks, also watch for run-level interruption/cancellation flags exposed on the run context (for example, a
speech_handle.interrupted
or a cancellation token) to detect premature termination. ◦ Optionally track the task handle externally so you can query or cancel it if needed. 1. Expose the state for consumers ◦ Provide a small API or in-memory map (or use Redis / DB for multi-process setups) that other parts of your system can query: is_in_tool(session_id) → true/false, current_tool(session_id) → metadata. If you tell me your SDK/language and whether tools are short- or long-lived, I’ll provide a short, targeted code sketch showing how to subscribe to events and flip the external state safely.
a
I'm using the js sdk
t
Thanks — I’m responding to your request for a JavaScript SDK example to track from outside the tools whether an agent is currently in a tool context. Below is a concise, practical pattern you can adopt. It uses session event listeners to maintain an external state map that marks sessions as "in tool" or "out of tool", and correlates start/completion events by run or conversation item IDs to avoid races. Persist the map in memory for a single process or use Redis/DB for multi-process setups. 1) High-level approach • Listen for agent session events such as
conversation_item_added
(tool call start or tool output) and any explicit function-complete / function-error / cancellation events. • When you detect a function-call start event, mark the session as in-tool and record the run id and tool name. • When you detect the corresponding function completion / output / cancellation event for that run id, mark the session out-of-tool. • For long-running tools, additionally track run cancellation/interruption flags if exposed on events or run metadata. 2) Minimal JS sketch (event-driven) • Replace
agentSession
and event names with the actual JS SDK objects and event names you have (this sketch assumes the JS SDK emits
conversation_item_added
and that conversation item messages include
type
,
run_id
, and `role`/`content` or similar fields).
Copy code
// sessionToolTracker.js

// In-memory map: sessionId -> { state: 'in_tool'|'out_of_tool', runId, toolName, startedAt }
const sessionState = new Map();

// Utility functions
function markInTool(sessionId, runId, toolName) {
  sessionState.set(sessionId, {
    state: 'in_tool',
    runId,
    toolName,
    startedAt: Date.now(),
  });
}

function markOutOfTool(sessionId, runId) {
  const cur = sessionState.get(sessionId);
  // Only clear if runId matches to avoid races
  if (cur && cur.runId === runId) {
    sessionState.set(sessionId, { state: 'out_of_tool' });
  }
}

function isInTool(sessionId) {
  const s = sessionState.get(sessionId);
  return s && s.state === 'in_tool';
}

// Subscribe to session events
function attachSessionListeners(agentSession) {
  const sessionId = agentSession.id; // adapt to actual SDK property

  agentSession.on('conversation_item_added', (item) => {
    // Example item shape assumptions:
    // item.type === 'function_call' (start)
    // item.type === 'function_result' (completion)
    // item.run_id is present to correlate
    // adapt to actual SDK event payload
    if (item.type === 'function_call') {
      // tool started
      markInTool(sessionId, item.run_id, item.tool_name || item.name);
      console.log(`[${sessionId}] tool started: ${item.tool_name} run=${item.run_id}`);
    } else if (item.type === 'function_result' || item.type === 'function_error') {
      // tool finished or errored
      markOutOfTool(sessionId, item.run_id);
      console.log(`[${sessionId}] tool finished: run=${item.run_id}`);
    }
  });

  // Optional: listen for explicit cancellation/interrupt events if SDK emits them
  agentSession.on('run_cancelled', (payload) => {
    // payload.run_id
    markOutOfTool(sessionId, payload.run_id);
    console.log(`[${sessionId}] run cancelled: run=${payload.run_id}`);
  });

  // Clean up on session end
  agentSession.on('session_finished', () => {
    sessionState.delete(sessionId);
  });
}

// Exported for other modules to query
module.exports = {
  attachSessionListeners,
  isInTool,
  sessionState, // optional export for debugging or persistence
};
3) Notes and robustness tips • Correlate by run id (or conversation item id) rather than just session id to avoid flipping state incorrectly when multiple tools are invoked in quick succession. • If tools can be nested or concurrent, store a stack or counter per session instead of a single run id. • For long-running/cancellable tools, listen for interruption or cancellation events (or check
run_ctx.speech_handle.interrupted
equivalent if surfaced via events) so you can mark out-of-tool when cancelled. • Persist state to Redis or a DB when tracking across multiple processes or servers. • Expose a small query API (e.g.,
isInTool(sessionId)
or
getCurrentTool(sessionId)
) so other parts of your app can switch behavior based on context. If you want, tell me: • The exact event names and payload fields your JS SDK instance emits (I can adapt the sketch to match them). • Whether tools can run concurrently or be nested (I’ll give a stack/counter variant). I can then give a more exact code sample matching your SDK’s event shapes.