How to Implement Page-Level Instructions with Dynamic getPageInstructions Callback in Page Agent

You can implement dynamic page-level instructions by supplying a getPageInstructions callback in your AgentConfig that receives the current page URL and returns situational guidance for the LLM.

Page Agent (alibaba/page-agent) extends beyond static system prompts by allowing URL-specific instruction injection. This capability lets you tailor the LLM’s behavior for individual websites or page patterns without modifying the core agent logic, making your web automation tasks more context-aware and precise.

Defining the Callback in AgentConfig

The configuration interface lives in packages/core/src/types.ts (lines 54-66). The instructions object accepts two optional properties: a static system string and the dynamic getPageInstructions function.

// packages/core/src/types.ts#L54-L66
export interface AgentConfig extends LLMConfig {
  // ...
  instructions?: {
    /** Global system-level instructions, applied to all tasks */
    system?: string

    /**
     * Dynamic page-level instructions callback
     * Called before each step to get instructions for the current page
     * @param url - Current page URL (window.location.href)
     * @returns Instructions string, or undefined/null to skip
     */
    getPageInstructions?: (url: string) => string | undefined | null
  }
  // ...
}

The callback receives the current URL as a string and may return instructions specific to that location, or undefined/null to skip page-level guidance for that step.

Runtime Execution Flow

During each step, the private #getInstructions() method in packages/core/src/PageAgentCore.ts (lines 62-80) constructs the final instruction block. It fetches the current URL from the browser state, conditionally invokes your callback, and sanitizes the output.

// packages/core/src/PageAgentCore.ts#L62-L80
async #getInstructions(): Promise<string> {
  const { instructions, experimentalLlmsTxt } = this.config
  const systemInstructions = instructions?.system?.trim()
  let pageInstructions: string | undefined

  const url = this.#states.browserState?.url || ''
  if (instructions?.getPageInstructions && url) {
    try {
      pageInstructions = instructions.getPageInstructions(url)?.trim()
    } catch (error) {
      console.error('[PageAgent] Failed to execute getPageInstructions callback:', error)
    }
  }
  // ...
}

If the callback returns a non-empty string, the method wraps it in <page_instructions> tags and concatenates it with the system instructions (and optional llms.txt content) to form the complete prompt block sent to the LLM. This logic continues through lines 86-99 in the same file, where the XML fragments are assembled.

Implementation Examples

Basic Usage with PageAgent

For standard UI-enabled automation, pass the configuration when instantiating PageAgent:

import { PageAgent } from 'page-agent'
import { AgentConfig } from '@page-agent/core'

const config: AgentConfig = {
  instructions: {
    system: 'You are a helpful web-automation assistant.',
    getPageInstructions: (url) => {
      if (url.includes('github.com')) {
        return 'When interacting with GitHub, avoid clicking on ads and focus on repository navigation.'
      }
      if (url.includes('example.com')) {
        return 'Only fill the contact form fields marked with an asterisk.'
      }
      return undefined
    },
  },
}

const agent = new PageAgent(config)
await agent.runTask('Search for open-source AI agents')

The agent automatically invokes the callback before each LLM call, injecting GitHub-specific guidance when browsing GitHub and form-filling rules when on example.com.

Headless Operation with PageAgentCore

For CI pipelines or headless environments, use PageAgentCore directly with the same configuration pattern:

import { PageAgentCore } from '@page-agent/core'
import type { AgentConfig } from '@page-agent/core'

const cfg: AgentConfig = {
  instructions: {
    system: 'You are a data-extraction bot.',
    getPageInstructions: (url) => {
      const match = url.match(/\/product\/(\d+)/)
      if (match) {
        return `Extract the product name, price, and availability for product ID ${match[1]}.`
      }
      return undefined
    },
  },
}

const core = new PageAgentCore(cfg)
await core.runTask('Collect product data from the current page')

Ensure the browserState.url is populated via the PageController before invoking tasks so the callback receives the correct location.

Async Instruction Generation

The callback supports asynchronous operations if you need to fetch configuration data remotely:

const config: AgentConfig = {
  instructions: {
    getPageInstructions: async (url) => {
      const resp = await fetch(`https://config-service/rules?site=${encodeURIComponent(url)}`)
      if (resp.ok) {
        const { rules } = await resp.json()
        return `Follow these rules: ${rules.join('; ')}`
      }
      return undefined
    },
  },
}

Because #getInstructions() is an async method (as shown in the source at line 62), it properly awaits your callback before constructing the <instructions> block.

Summary

  • Configuration location: Define getPageInstructions inside the instructions object of AgentConfig in packages/core/src/types.ts.
  • Runtime invocation: The #getInstructions() method in packages/core/src/PageAgentCore.ts calls your function with the current URL from browserState before every LLM step.
  • Return behavior: Return a string to inject page-specific guidance, or undefined/null to omit page-level instructions for that URL.
  • Error handling: The core wraps callback execution in a try-catch block (lines 71-75) to prevent agent crashes from user-provided logic.
  • Composition: Page instructions are wrapped in <page_instructions> tags and prepended to the system prompt, creating a layered instruction hierarchy.

Frequently Asked Questions

What is the exact function signature for getPageInstructions?

According to the AgentConfig interface in packages/core/src/types.ts, the signature is (url: string) => string | undefined | null. The function receives the current page URL (equivalent to window.location.href) and should return either an instruction string or a falsy value to skip injection for that page.

Can getPageInstructions be an async function?

Yes. While the interface defines the return type as string | undefined | null, the consuming method #getInstructions() in packages/core/src/PageAgentCore.ts is declared as async, so you may return a Promise<string | undefined | null>. The agent will await the resolution before building the prompt.

How do page-level instructions interact with system instructions?

Page instructions supplement rather than replace system instructions. As implemented in PageAgentCore.ts (lines 86-99), the agent concatenates the system string with the returned page instructions (wrapped in <page_instructions> tags) into a single <instructions> block. The LLM receives both contexts simultaneously.

Where should I implement URL matching logic?

Implement conditional logic directly inside the getPageInstructions callback body. The source code in packages/core/src/PageAgentCore.ts passes the raw URL string from this.#states.browserState.url, allowing you to use methods like String.prototype.includes(), regular expressions, or URL object parsing to determine which instructions to return for specific domains or path patterns.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →