Caching AI planning & locate

Midscene supports caching Plan steps and matched DOM element information to reduce AI model calls and greatly improve execution efficiency. Please note that DOM element cache is only supported for web automation tasks.

Effect

With caching hit, time cost is significantly reduced. For example, in the following case, execution time was reduced from 51 seconds to 28 seconds.

  • before

  • after

Cache files and storage

Midscene's caching mechanism is based on input stability and output reusability. When the same task instructions are repeatedly executed in similar page environments, Midscene will prioritize using cached results to avoid repeated AI model calls, significantly improving execution efficiency.

The core caching mechanisms include:

  • Task instruction caching: For planning operations (such as ai, aiAction), Midscene uses the prompt instruction as the cache key to store the execution plan returned by AI
  • Element location caching: For location operations (such as aiLocate, aiTap), the system uses the location prompt as the cache key to store element XPath information, and verifies whether the XPath is still valid on the next execution
  • Invalidation mechanism: When cache becomes invalid, the system automatically falls back to AI model for re-analysis
  • Never cache query results: The query results like aiBoolean, aiQuery, aiAssert will never be cached.

Cache contents will be saved in the ./midscene_run/cache directory with the .cache.yaml as the extension name.

Cache strategies

By configuring the cache option, you can enable caching for your agent.

Disable cache

Configuration: cache: false or not configuring the cache option

Completely disable cache functionality, always call AI model for every operation. Suitable when you need real-time results or for debugging. By default, if you don't configure the cache option, caching is disabled.

// Direct Agent creation
const agent = new PuppeteerAgent(page, {
  cache: false,
});
# YAML configuration
agent:
  cache: false

Read-write mode

Configuration: cache: { id: "my-cache-id" } or cache: { strategy: "read-write", id: "my-cache-id" }

Automatically read existing cache and update cache files during execution. The default value of strategy is read-write.

// Direct Agent creation - explicit cache ID
const agent = new PuppeteerAgent(page, {
  cache: { id: "my-cache-id" },
});

// Explicitly specify strategy
const agent = new PuppeteerAgent(page, {
  cache: { strategy: "read-write", id: "my-cache-id" },
});
# YAML configuration - explicit cache ID
agent:
  cache:
    id: "my-cache-test"

# Explicitly specify strategy
agent:
  cache:
    id: "my-cache-test"
    strategy: "read-write"

YAML mode also supports cache: true to automatically use the file name as the cache ID.

Read-only, manual write

Configuration: cache: { strategy: "read-only", id: "my-cache-id" }

Only read cache, no automatic writing to cache files. Requires manual agent.flushCache() call to write cache files. Suitable for production environments to ensure cache consistency.

// Direct Agent creation
const agent = new PuppeteerAgent(page, {
  cache: { strategy: "read-only", id: "my-cache-id" },
});

// Manual cache write required
await agent.flushCache();
# YAML configuration
agent:
  cache:
    id: "my-cache-test"
    strategy: "read-only"

Configuration via MIDSCENE_CACHE=1 environment variable with cacheId, equivalent to read-write mode.

// Old way, requires MIDSCENE_CACHE=1 environment variable and cacheId
const agent = new PuppeteerAgent(originPage, {
  cacheId: 'puppeteer-swag-sab'
});
MIDSCENE_CACHE=1 tsx demo.ts

Using Playwright AI Fixture from @midscene/web/playwright

When using PlaywrightAiFixture from @midscene/web/playwright, pass the same cache options to control caching behaviour.

Disable cache

// fixture.ts in sample code
export const test = base.extend<PlayWrightAiFixtureType>(
  PlaywrightAiFixture({
    cache: false,
  }),
);

Read-write mode

// fixture.ts in sample code
// Auto-generate cache ID from test metadata
export const test = base.extend<PlayWrightAiFixtureType>(
  PlaywrightAiFixture({
    cache: true,
  }),
);

// fixture.ts in sample code
// Explicitly provide cache ID
export const test = base.extend<PlayWrightAiFixtureType>(
  PlaywrightAiFixture({
    cache: { id: "my-fixture-cache" },
  }),
);

Read-only, manual write

// fixture.ts in sample code
export const test = base.extend<PlayWrightAiFixtureType>(
  PlaywrightAiFixture({
    cache: { strategy: "read-only", id: "readonly-cache" },
  }),
);

When you run the fixture in read-only mode you need to manually persist the cache after your test steps. Use the agentForPage helper provided by the fixture to fetch the underlying agent, then call agent.flushCache() at the point where you want to write the cache file:

test.afterEach(async ({ page, agentForPage }, testInfo) => {
  // Only flush cache if the test passed
  if (testInfo.status === 'passed') {
    console.log('Test passed, flushing Midscene cache...');
    const agent = await agentForPage(page);
    await agent.flushCache();
  } else {
    console.log(`Test ${testInfo.status}, skipping Midscene cache flush.`);
  }
});

test('manual cache flush', async ({ agentForPage, page, aiTap, aiWaitFor }) => {
  const agent = await agentForPage(page);

  await aiTap('first highlighted link in the hero section');
  await aiWaitFor('the detail page loads completely');

  await agent.flushCache();
});

FAQ

No cache file is generated

Please ensure you have correctly configured caching:

  1. Direct Agent creation: Set cache: { id: "your-cache-id" } in the constructor
  2. Playwright AI Fixture mode: Set cache: true or cache: { id: "your-cache-id" } in fixture configuration
  3. YAML script mode: Set agent.cache.id in the YAML file
  4. Read-only mode: Ensure you called the agent.flushCache() method
  5. Legacy approach: Set cacheId and enable MIDSCENE_CACHE=1 environment variable

How to check if the cache is hit?

You can view the report file. If the cache is hit, you will see the cache tip and the time cost is obviously reduced.

Why the cache is missed on CI?

You need to commit the cache files to the repository in CI and recheck the cache hit conditions.

Does it mean that AI services are no longer needed after using cache?

No. Caching is the way to accelerate the execution, but it's not a tool for ensuring long-term script stability. We have noticed many scenarios where the cache may miss when the DOM structure changes. AI services are still needed to reevaluate the task when the cache miss occurs.

How to manually remove the cache?

You can remove the cache file in the ./midscene_run/cache directory, or edit the contents in the cache file.

How to disable the cache for a single API?

You can use the cacheable option to disable the cache for a single API.

Please refer to the documentation of the corresponding API for details.

Limitations of XPath in caching element location

Midscene uses XPath to cache the element location. ⁠We are using a relatively strict strategy to prevent false matches. In these situations, the cache will not be accessed.

  1. The text content of the new element at the same XPath is different from the cached element.
  2. The DOM structure of the page is changed from the cached one.

When the cache is not hit, the process will fall back to continue using AI services to find the element.

Get more debug logs for caching

You can set the DEBUG=midscene:cache:* environment variable to get more debug logs for caching.