Welcome back! In the previous chapter, Session Lifecycle Management, we learned how to manage the "Meeting" (Session) and the "Room" (Project Root).
Now that we know who is in the meeting and where they are, we need to establish the Rules of Engagement.
Is the agent allowed to act on its own? Is it currently brainstorming a plan? Has it been left alone for a long time? This is Agent Context & Mode Tracking.
Imagine you hired a contractor to renovate your kitchen. You interact with them in different "modes":
Without Mode Tracking, the agent wouldn't know how to behave. It might try to install a cabinet while you are still drawing the blueprint, or it might stop to ask for permission when you explicitly told it to run automatically.
In bootstrap, we use Context Flags in the Global State to track these behaviors.
isInteractive)This is the master switch.
This is a specific optimization for AI. When we send data to the AI model (Anthropic's API), we want to use Prompt Caching to save money and time.
If we constantly toggle settings on and off, we "break" the cache. A Latch is a flag that, once turned on, stays on for the rest of the session to keep the cache stable.
We interact with these modes using simple functions exported from state.ts.
Before asking for user input (like a confirmation prompt), we must check if a human is actually there.
import { getIsInteractive } from './state.js'
function askForPermission() {
if (!getIsInteractive()) {
// Don't block! Default to a safe action or fail.
console.log("No user present, skipping permission...")
return
}
// ... show dialog ...
}
When the user types /plan, we switch modes. The system needs to know about this transition to handle UI updates (like showing a "Exiting Plan Mode" notification later).
import { handlePlanModeTransition } from './state.js'
// User types: /plan
handlePlanModeTransition('auto', 'plan')
// Later, user says: "Go ahead"
handlePlanModeTransition('plan', 'auto')
If the user steps away (AFK - Away From Keyboard), we enable a special header to tell the API to cache differently. Once enabled, we keep it enabled.
import { getAfkModeHeaderLatched, setAfkModeHeaderLatched } from './state.js'
function updateHeaders() {
// If it was EVER on, keep it on
if (getAfkModeHeaderLatched()) {
return { 'anthropic-beta': 'prompt-caching-2024-07-31' }
}
}
How does the system decide what to show the user? It acts like a state machine. Let's visualize a user entering "Plan Mode" and then exiting it.
/plan. State updates.
Let's look at how state.ts implements this tracking.
We don't just flip a boolean. We look at where we came from and where we are going. This allows us to trigger specific UI elements, like the "Plan Mode Exit Summary."
// state.ts
export function handlePlanModeTransition(fromMode: string, toMode: string): void {
// If we are leaving plan mode...
if (fromMode === 'plan' && toMode !== 'plan') {
// ...flag that we need to show the summary attachment
STATE.needsPlanModeExitAttachment = true
}
// If entering plan mode, clear old flags
if (toMode === 'plan' && fromMode !== 'plan') {
STATE.needsPlanModeExitAttachment = false
}
}
Here is the implementation of the "Sticky" flag. Notice there is no "Turn Off" function for the latch during a session. This is intentional to preserve the API cache.
// state.ts
// This variable stores the state. null = not set yet.
// afkModeHeaderLatched: boolean | null
export function getAfkModeHeaderLatched(): boolean | null {
return STATE.afkModeHeaderLatched
}
export function setAfkModeHeaderLatched(v: boolean): void {
// Once true, it stays true (conceptually)
STATE.afkModeHeaderLatched = v
}
Context isn't just about modes; it's also about what the agent has done. We track invokedSkills to ensure that if we compress the conversation history (to save space), we don't forget which important tools (skills) were used.
// state.ts
export function addInvokedSkill(
skillName: string,
content: string
): void {
// Store what we did so we don't forget it later
STATE.invokedSkills.set(skillName, {
skillName,
content,
invokedAt: Date.now()
})
}
Context tracking is the decision-making brain that guides the other systems:
isInteractive, needsPlanModeExitAttachment) live in the STATE object we built in Global Application State.afkModeHeaderLatched) exist specifically to optimize the Prompt Cache, which directly lowers the bill. We discuss costs in Resource & Cost Accounting.In this chapter, we learned:
isInteractive determines if the agent can ask the user for help.Now that the agent knows who it is (Session) and what mode it is in (Context), we need to track the most painful part of any project: The Budget.
Next Chapter: Resource & Cost Accounting
Generated by Code IQ