This prompt is for infrastructure teams building AI agents that call external tools returning time-sensitive data. It solves the problem of an agent naively reusing a cached tool result that has become stale, or wasting resources by refreshing data that is still valid. Use this prompt when your agent's tool results have a known shelf life, when the cost of a stale decision exceeds the cost of a refresh call, or when you need an auditable decision trail for why a result was reused or refreshed.
Prompt
Tool Result Expiry and Refresh Prompt Template

When to Use This Prompt
Defines the operational conditions and architectural prerequisites for deploying the Tool Result Expiry and Refresh Prompt Template in a production agent system.
Deploy this prompt when you have already instrumented your tool layer to return structured metadata alongside each result. The prompt expects a [TOOL_OUTPUT] that includes a timestamp, a declared TTL, and a unique result identifier. It is designed for high-stakes operational domains—such as incident response, financial reconciliation, or deployment verification—where acting on data that is even a few minutes old can cause cascading failures. Do not use this prompt for user-facing chat memory or personalization; those workflows require session-scoped eviction strategies, not per-result expiry logic. This prompt also assumes your agent has a deterministic cache layer available as a fallback, and that the model's role is to reason about the decision to refresh, not to implement the cache itself.
Before integrating this prompt, ensure your evaluation harness can measure two distinct failure modes: false staleness (refreshing a result that was still valid, wasting latency and cost) and missed expiry (reusing a result that had expired, leading to incorrect downstream actions). If you cannot instrument both metrics, you are not ready to tune this prompt. The next section provides the copy-ready template. Wire it into your agent's pre-tool-call reasoning step, not as a post-hoc audit log.
Use Case Fit
Where the Tool Result Expiry and Refresh Prompt Template delivers value and where it introduces risk. Use these cards to decide if this pattern fits your infrastructure before embedding it in a production agent loop.
Good Fit: Time-Sensitive Tool Data
Use when: tool results have a known shelf life (e.g., stock prices, weather, status checks). Guardrail: embed explicit expires_at timestamps in tool output metadata and enforce refresh only after expiry.
Bad Fit: Immutable or Archival Records
Avoid when: tool results represent fixed historical facts (e.g., a commit hash, a closed ticket). Guardrail: mark results as immutable: true in the contract to prevent unnecessary refresh calls that waste tokens and API quota.
Required Input: Explicit TTL Contract
What to watch: the prompt cannot guess expiry. Guardrail: every tool definition must include a cache_ttl_seconds field. The prompt reads this contract; if missing, it defaults to a safe short TTL and logs a schema warning.
Operational Risk: Cache Stampede on Expiry
What to watch: multiple concurrent agent steps all refreshing the same expired result simultaneously. Guardrail: implement a single-flight lock at the infrastructure layer so the prompt's refresh decision triggers one call, with other steps waiting for the fresh result.
Operational Risk: Stale-While-Revalidate Confusion
What to watch: the agent uses a stale result while a refresh is in flight, leading to inconsistent reasoning. Guardrail: the prompt must annotate results with stale_status: "fresh" | "expired" | "refreshing" and instruct the agent to wait or degrade gracefully when status is refreshing.
Eval Trap: Silent Expiry Drift
What to watch: a result's TTL passes but the agent continues using it because no downstream step checks the timestamp. Guardrail: include an eval that injects an expired result and asserts the agent either refreshes or explicitly flags the data as stale before acting on it.
Copy-Ready Prompt Template
A reusable prompt that annotates tool results with expiry metadata and decides when to refresh versus reuse cached data.
This prompt template is designed to be injected into your agent's tool-response processing layer. It receives a tool result, the current time, and any relevant caching policy, then outputs a structured annotation that includes an expiry timestamp, a refresh decision, and the reasoning behind that decision. The template uses square-bracket placeholders that you must replace with values from your application's state manager, tool registry, or context window before sending the request to the model.
textYou are a tool-result freshness evaluator. Your job is to annotate a tool result with expiry metadata and decide whether the result should be refreshed or reused. ## INPUT - Current time: [CURRENT_TIMESTAMP] - Tool name: [TOOL_NAME] - Tool call arguments: [TOOL_ARGUMENTS] - Tool result: [TOOL_RESULT] - Caching policy for this tool: [CACHING_POLICY] - Prior refresh history for this tool call signature: [REFRESH_HISTORY] ## TASK 1. Determine the expiry timestamp for this result based on the caching policy, the nature of the data, and any time-sensitivity hints in the result itself. 2. Decide whether the result should be REFRESHED or REUSED. 3. Provide a concise reason for your decision. ## CONSTRAINTS - If the caching policy specifies a TTL, use it as the maximum expiry window unless the result contains explicit server-provided expiry headers. - If the result contains an error, timeout, or partial data, mark it as REFRESH with an immediate expiry. - If the result is older than the TTL at the current time, mark it as REFRESH. - If the refresh history shows more than [MAX_CONSECUTIVE_REFRESHES] consecutive refreshes for the same arguments, mark as REUSED and flag for human review. - Never invent expiry times. If no policy or data-driven hint exists, default to [DEFAULT_TTL_SECONDS] seconds from the result's retrieval time. ## OUTPUT SCHEMA Return a single JSON object with no additional text: { "tool_name": "string", "result_retrieved_at": "ISO8601 timestamp", "expires_at": "ISO8601 timestamp or null if already expired", "decision": "REFRESH | REUSE", "reason": "string (max 200 characters)", "requires_human_review": boolean }
To adapt this template, replace each square-bracket placeholder with values from your tool execution harness. [CACHING_POLICY] should be a structured description of the tool's TTL, invalidation conditions, and scope boundaries—ideally sourced from your tool registry. [REFRESH_HISTORY] should include timestamps and outcomes of recent calls with the same tool and arguments, enabling the model to detect refresh loops. [MAX_CONSECUTIVE_REFRESHES] and [DEFAULT_TTL_SECONDS] are configuration constants you should set based on your system's tolerance for stale data and redundant tool calls. If your application cannot provide a structured caching policy, replace that placeholder with a static rule set such as "financial data expires in 60 seconds; static reference data expires in 3600 seconds."
Before deploying this prompt into a production agent loop, validate the model's output against your expected schema. A common failure mode is the model returning an expiry timestamp that is already in the past when the decision is REUSE, or returning REUSE for an error response. Add a post-processing validator that rejects any annotation where decision is REUSE but expires_at is earlier than result_retrieved_at, and any annotation where the tool result contains an error string but decision is not REFRESH. For high-risk domains where stale data could cause incorrect actions—such as financial transactions or clinical data lookups—route any requires_human_review: true annotation to a review queue and log the full annotation alongside the original tool result for auditability.
Prompt Variables
Placeholders required by the Tool Result Expiry and Refresh Prompt Template. Each variable must be populated before the prompt is assembled. Validation checks prevent stale data reuse and unnecessary refresh calls in production.
| Placeholder | Purpose | Example | Validation Notes |
|---|---|---|---|
[TOOL_RESULT_PAYLOAD] | The raw output from a tool call that may be cached or reused | {"price": 142.30, "timestamp": "2025-03-15T10:00:00Z"} | Must be valid JSON. Parse check required. Null allowed only if tool returned no data. Schema must match the tool's declared output contract. |
[TOOL_NAME] | Identifier for the tool that produced the result, used for cache key construction and invalidation rules | fetch_stock_price | Must match a registered tool name in the agent's tool registry. Non-empty string. Used to look up per-tool TTL and refresh policies. |
[RESULT_AGE_SECONDS] | Elapsed time since the tool result was produced, computed by the harness before prompt assembly | 45 | Must be a non-negative integer. Harness must compute from result timestamp and current clock. If timestamp is missing, set to null and flag for refresh. |
[TOOL_TTL_SECONDS] | Maximum age in seconds before this tool's results are considered expired, defined per tool in the caching policy | 60 | Must be a positive integer. Retrieved from tool-specific caching policy config. If null or missing, default to 0 (always refresh). Do not hardcode in prompt. |
[DEPENDENCY_STATE_HASH] | Hash of upstream tool results that this result depends on, used to detect stale cached results when dependencies change | a3f2b1c9d4 | Must be a non-empty string if dependencies exist. Harness must compute from current dependency outputs. If hash differs from cached hash, result is stale regardless of age. |
[CURRENT_QUERY_INTENT] | The user's current request or agent's current goal, used to decide if cached result is still contextually relevant | What is the current price of AAPL? | Must be a non-empty string. Harness should compare semantic relevance to the original query that produced the cached result. Null if no user query context available. |
[CACHE_SCOPE] | Boundary within which the cached result is valid: session, user, or global | session | Must be one of: session, user, global. Retrieved from tool caching policy. Cross-session cache reuse requires explicit opt-in. Mismatch with current scope triggers refresh. |
[REFRESH_COST_ESTIMATE] | Estimated cost or latency of a refresh call, used to weigh against staleness risk | low | Must be one of: low, medium, high. Retrieved from tool metadata. If high, prompt should bias toward reuse when safe. If low, prompt should bias toward refresh when uncertain. |
Implementation Harness Notes
How to wire the Tool Result Expiry and Refresh prompt into a production agent harness with validation, caching, and observability.
The Tool Result Expiry and Refresh prompt is not a standalone artifact—it is a decision module that sits between your tool execution layer and the agent's reasoning context. In practice, you will invoke this prompt every time a tool result is about to be passed into the model's context window, or when the agent explicitly requests a tool call that might be served from cache. The harness is responsible for: (1) attaching expiry metadata to every tool result as it arrives, (2) calling the expiry/refresh prompt with the current time, the cached result, and the tool's refresh cost, (3) parsing the structured decision output, and (4) either injecting the cached result, triggering a refresh call, or blocking the agent with a staleness warning.
The prompt expects a specific input shape. Your harness must assemble a JSON object containing: current_timestamp (ISO-8601), tool_name, cached_result (the full payload from the prior call), result_timestamp (when the result was originally fetched), ttl_seconds (the declared time-to-live for this tool's results), refresh_cost (a numeric or categorical estimate of latency/token/dollar cost to refresh), and dependency_state (a map of upstream tool results this result depends on, with their own timestamps). The output schema must be enforced: a JSON object with decision (one of USE_CACHED, REFRESH, BLOCK_STALE), confidence (0-1), reasoning (a short string for logs), and suggested_next_refresh_check (ISO-8601). Use structured output mode or a JSON schema validator in your model API call. If the model returns an invalid decision value or missing fields, your harness must default to BLOCK_STALE and log the parse failure—never silently inject unvalidated cached data into the agent's context.
Retry logic is critical here. If the harness decides to REFRESH and the subsequent tool call fails (timeout, 5xx, rate limit), do not retry the expiry prompt itself. Instead, implement a fallback chain: first, check if the cached result is within a grace period (e.g., 2x TTL for read-only data). If within grace, inject the cached result with a stale_flag: true annotation so the agent can reason about data freshness. If beyond grace, escalate to BLOCK_STALE and surface the failure to the agent with a clear message: 'Tool [tool_name] result is expired and refresh failed. Provide a partial response or ask the user for guidance.' Log every decision—USE_CACHED, REFRESH, BLOCK_STALE, and fallback—with the tool name, timestamps, TTL, and decision reasoning. This log becomes your audit trail for debugging agent errors caused by stale data.
Model choice matters. For low-latency, high-throughput agents, use a fast classifier model (e.g., a small fine-tuned model or a rapid-inference endpoint) for the expiry decision, reserving larger models for the agent's core reasoning. The expiry prompt is a classification task with a constrained output schema, so it benefits from models with strong instruction-following and JSON mode support. If you are using the same model for both the agent and the expiry check, be aware of context window pressure: the expiry prompt's input includes the full cached result, which may be large. Consider compressing cached results before passing them to the expiry prompt, or using a separate, smaller context window for expiry decisions.
Testing this harness requires a dedicated eval suite. Build test cases for: (1) a result well within TTL—expect USE_CACHED with high confidence; (2) a result just past TTL but with low refresh cost—expect REFRESH; (3) a result far past TTL with high refresh cost and stale dependencies—expect BLOCK_STALE; (4) a result with a dependency that updated more recently than the result itself—expect REFRESH even if within TTL; (5) malformed input (missing timestamp, invalid TTL)—expect the harness to reject and log before calling the model. Run these evals on every prompt or model version change. In high-risk domains (finance, healthcare, safety-critical operations), add a human-review gate for any BLOCK_STALE decision before the agent's response reaches the user. The harness should also emit a metric—stale_result_blocks_total—so you can monitor whether your TTLs are tuned correctly or causing excessive blocking.
Expected Output Contract
Defines the structured output schema for the Tool Result Expiry and Refresh prompt. Use this contract to validate that the model's response contains all required fields, correctly typed, and with actionable refresh decisions. Integrate this schema into your application's post-processing validator before caching or reusing tool results.
| Field or Element | Type or Format | Required | Validation Rule |
|---|---|---|---|
tool_result_id | string (UUID or hash) | Must match the ID of the tool call being annotated. Non-empty and present in the request context. | |
cached_at_timestamp | ISO 8601 UTC string | Must be a valid ISO 8601 datetime. Must not be in the future. Parseable by standard datetime libraries. | |
expires_at_timestamp | ISO 8601 UTC string or null | If null, the result never expires. If set, must be after cached_at_timestamp. Required for time-sensitive data. | |
refresh_decision | enum: [REFRESH, REUSE, STALE_ONLY] | Must be one of the three allowed values. REFRESH triggers a new tool call. REUSE returns the cached result. STALE_ONLY permits reuse if not yet expired. | |
confidence_score | float between 0.0 and 1.0 | Model's confidence in the refresh_decision. Must be a number. Values below 0.5 should trigger a human review or forced refresh in high-stakes contexts. | |
stale_indicators | array of strings | If refresh_decision is REFRESH, this array should contain at least one reason (e.g., 'age_exceeded', 'dependency_changed'). Empty array is allowed for REUSE decisions. | |
cached_payload_summary | string | A brief, human-readable summary of the cached data. Must not exceed 200 characters. Used for debugging and audit trails. Null allowed if no prior cache exists. | |
dependency_versions | object (map of string to string) | Key-value pairs representing the versions of upstream data sources when cached. Used to detect dependency-driven staleness. Empty object allowed if no dependencies exist. |
Common Failure Modes
Tool result expiry and refresh logic fails silently in production, leading to agents acting on stale data or burning budget on redundant calls. These are the most common failure patterns and how to prevent them.
Agent Ignores Expiry Metadata
What to watch: The prompt includes TTL or expiry fields in tool results, but the agent treats all cached data as equally valid. It proceeds with hours-old data for a time-sensitive query without triggering a refresh. Guardrail: Add an explicit pre-reasoning step in the system prompt that checks the expires_at field before any cached result is used. If current_time > expires_at, the result must be discarded and the tool re-invoked.
Unnecessary Refresh Storms
What to watch: The agent defaults to refreshing every tool call regardless of cache validity, causing rate-limit exhaustion and cost overruns. This often happens when the refresh policy is too aggressive or the expiry window is undefined. Guardrail: Implement a cache policy with explicit cache_until timestamps and instruct the agent to reuse results when current_time <= cache_until. Log refresh decisions to monitor hit/miss ratios.
Stale Dependency Chain Corruption
What to watch: Tool B depends on the output of Tool A. Tool A's result expires, but Tool B's cached result—derived from the stale data—does not. The agent uses Tool B's output, assuming it is still valid. Guardrail: Tag all cached results with a depends_on field listing upstream tool call IDs and their expiry times. Before using any cached result, validate that all upstream dependencies are still fresh.
Partial Refresh and State Inconsistency
What to watch: The agent refreshes only one of several interdependent tool results, creating a mismatch between fresh and stale data in the same reasoning step. This produces outputs that are internally inconsistent. Guardrail: Define atomic refresh groups in the prompt. If any member of a group expires, the entire group must be refreshed together. Validate group consistency before proceeding to downstream reasoning.
Expiry Metadata Stripped by Tool Proxy
What to watch: A middleware layer, MCP server, or tool proxy strips the expires_at or cache_control headers from tool responses before they reach the agent. The agent has no way to know the data is time-sensitive. Guardrail: Enforce a tool output contract that requires expiry metadata in a known schema field. Validate at the agent boundary that this field is present and reject or flag responses missing it.
Clock Skew Between Agent and Tool
What to watch: The agent's current_time and the tool server's clock diverge, causing the agent to miscalculate whether a cached result is still valid. A result the tool considers expired may appear fresh to the agent, or vice versa. Guardrail: Include the tool server's timestamp in every cached result alongside the expiry. Instruct the agent to compare expiry against the tool's timestamp, not its own clock, when making refresh decisions.
Evaluation Rubric
Use this rubric to test whether the prompt correctly decides to refresh or reuse cached tool results. Run each criterion against a set of prepared test cases before shipping.
| Criterion | Pass Standard | Failure Signal | Test Method |
|---|---|---|---|
Expiry metadata annotation | Every tool result in the output includes a valid | Missing expiry field on any result; expiry timestamp in the past for a result marked as fresh; TTL value that contradicts the tool's known SLA | Parse output JSON; assert |
Stale result rejection | Prompt refuses to reuse a cached result when the current time exceeds the result's expiry timestamp | Prompt returns a stale result without a refresh call; prompt uses expired data in downstream reasoning without marking it as degraded | Inject a test case with a known-expired cache entry; assert the output either triggers a refresh tool call or explicitly marks the result as expired and abstains from using it |
Fresh result reuse | Prompt reuses a cached result without an unnecessary refresh call when the result is within its TTL and no invalidation condition is met | Prompt issues a refresh tool call for a result that is still valid; prompt adds unnecessary latency or cost by re-fetching unchanged data | Provide a cache entry with 50% of TTL remaining and no dependency changes; assert no refresh tool call is made and the cached value appears in the output |
Dependency-triggered invalidation | Prompt detects that an upstream tool result has changed and invalidates downstream cached results that depend on it, triggering a refresh | Prompt reuses a downstream cached result after its upstream dependency was refreshed; prompt fails to propagate invalidation through the dependency chain | Chain two tool calls where Tool B depends on Tool A's output; refresh Tool A with a changed result; assert Tool B's cache is invalidated and a refresh is triggered |
Explicit invalidation condition handling | Prompt respects tool-specific invalidation rules beyond TTL, such as user role change, schema version bump, or error state | Prompt ignores a documented invalidation condition and serves a stale result; prompt applies a generic TTL check when a specific invalidation rule should override it | Set a test case where TTL is still valid but a tool-specific invalidation flag is set; assert the prompt triggers a refresh despite the unexpired TTL |
Partial refresh scoping | Prompt refreshes only the expired or invalidated subset of results rather than re-fetching all cached data | Prompt issues a blanket refresh of all tool results when only one has expired; prompt wastes tool call budget on unnecessary re-fetches | Provide a cache with three results where only one is expired; assert the output contains exactly one refresh tool call targeting the expired result |
Error state handling during refresh | Prompt detects a refresh failure, marks the result as stale with an error annotation, and does not silently use the expired value | Prompt ignores a refresh failure and proceeds with the expired result as if it were fresh; prompt retries indefinitely without escalation | Simulate a tool returning a 5xx error on refresh; assert the output marks the result as |
Enabling Efficiency, Speed & Accuracy
Intelligent Analysis, Decision & Execution
We build AI systems for teams that need search across company data, workflow automation across tools, or AI features inside products and internal software.
Talk to Us
Search across company data
Give teams answers from docs, tickets, runbooks, and product data with sources and permissions.
Useful when people spend too long searching or get different answers from different systems.

Automate internal workflows
Use AI to route work, draft outputs, trigger actions, and keep approvals and logs in place.
Useful when repetitive work moves across multiple tools and teams.

Add AI to products and internal tools
Build assistants, guided actions, or decision support into the software your team or customers already use.
Useful when AI needs to be part of the product, not a separate tool.
Adapt This Prompt
How to adapt
Add a strict JSON expiry contract to every tool result. Include cached_at, expires_at, cache_key, and invalidation_triggers fields. Wire the prompt to a caching layer that enforces TTL before the model sees results. Add retry logic for expired results.
codeFor every tool result, append this metadata block: { "cache_metadata": { "cached_at": "[ISO_TIMESTAMP]", "expires_at": "[ISO_TIMESTAMP]", "cache_key": "[TOOL_NAME]:[ARG_HASH]", "invalidation_triggers": ["[CONDITION_1]", "[CONDITION_2]"] } } Before using a cached result, check: 1. Is current_time < expires_at? 2. Have any invalidation_triggers fired? If either check fails, call the tool fresh. Do not use expired data.
Watch for
- Clock skew between the caching layer and the model's perception of time
- Invalidation triggers that are too broad, causing unnecessary refreshes
- Missing cache keys on some tool paths, leading to silent staleness

About the author
Prasad Kumkar
CEO & MD, Inference Systems
Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.
His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.
Partnered with leading AI, data, and software stack.
How We Work
Custom AI workflows for your Business
One-fit-all AI don't work for modern businesses. At Inferensys, we aim to understand your business & custom requirements; which we use to define most efficient agentic workflows, the data, and the tools for your business.
01
Review the use case
We understand the task, the users, and where AI can actually help.
Read more02
Pick the right approach
We define what needs search, automation, or product integration.
Read more03
Build the first useful version
We implement the part that proves the value first.
Read more04
Improve from there
We add the checks and visibility needed to keep it useful.
Read moreThe first call is a practical review of your use case and the right next step.
Talk to Us