Skip to content
Back to Blog

After Tool Results Leave the Prompt: Designing Safe Artifact References

Published Editorial policy & corrections

Editorial note: AI-assisted engineering analysis and proposed reference design. Primary sources checked November 6, 2026. The incident is hypothetical; no pinned LangChain or MemEx implementation was inspected or tested.

Share:XBSMRedditHNEmail

At 10:10, an infrastructure diagnostic agent asks a tool for an incident snapshot. The result is too large for its prompt, so the harness writes it to /tmp/incident.json and returns a preview. The preview shows failures in one region. The agent remembers the path and continues investigating.

At 10:12, another diagnostic operation writes a newer snapshot to the same location. At 10:14, the agent reopens the path to decide whether a restart is justified. The file exists. The read succeeds. But the bytes describe a different observation. The agent combines the first preview with the replacement snapshot and proposes an action neither result independently supports.

This is a hypothetical failure case, not a reported defect in LangChain or Databricks. It makes a particular engineering boundary visible: the contract between storing a tool result and using it later.

Moving data out of the prompt can be useful. It also means the agent’s reasoning depends on a storage and retrieval system whose behavior must remain interpretable after the original tool call has finished.

Two ways to move results outside the context window

LangChain’s October 14, 2026 engineering guide describes saving oversized tool results to files, returning a preview and file path, and recovering details through later paged reads. Its example uses a path derived from the tool call ID. The shared mutable filename in our opening is a deliberately simplified failure case, not a description of that implementation. LangChain: Context Engineering—How Deep Agents Remember.

Databricks’ May 19, 2026 MemEx report describes a persistent typed Python environment. Tool outputs stay as objects in scope across turns; code can filter, combine, and compute over them while exposing selected output to the model. It changes how the model interacts with intermediate results. Databricks: MemEx—A Programmable Scratchpad for LLM Agents.

These approaches motivate the same questions through different mechanisms. What observation does this reference identify? What happens when the storage or kernel changes? How much of the observation did the model actually inspect? Who may retrieve it now?

The sources describe their respective context-management approaches. Establishing how either implementation answers these questions requires a pinned release, code inspection, and tests. The design below is a proposal for implementers, not a security assessment of either product.

A locator is only part of a reference

A filename says where a read might begin. A variable name says where an object might be found in a particular scope. Neither alone guarantees immutable evidence identity.

Even a unique filename leaves other questions open. The file can disappear. Permissions can change. A write can stop halfway through. A result can be a complete response to a query that covered only one region. The underlying source can change while the captured bytes remain intact.

It helps to separate three checks:

CheckQuestionExample failure
Identity and integrityAre these the referenced bytes?A mutable locator now resolves to another snapshot.
ApplicabilityDo these observations satisfy this decision’s evidence needs?An intact snapshot omits a required region.
AuthorityMay this reader receive these bytes for this purpose now?Access was revoked after the first page.

Passing one check does not compensate for failing another. A checksum cannot grant access. An access grant cannot establish completeness. A complete old snapshot cannot establish that a live system is healthy now.

Give the result a retrieval contract

A useful starting point is a small descriptor issued by the runtime. This proposed ArtifactRef has ten top-level fields. Values are illustrative, and the hash is an explicit placeholder.

{
  "artifact_id": "art_incident_042",
  "content_hash": "sha256:<digest-of-exact-stored-bytes>",
  "tool_call_id": "call_incident_042",
  "schema_version": "example.incident-snapshot.v1",
  "created_at": "2026-11-06T04:40:00Z",
  "source_version": {
    "source_id": "infra.incident-events",
    "snapshot_id": "infra_snapshot_20261106_043950",
    "observed_at": "2026-11-06T04:39:50Z"
  },
  "completeness": {
    "status": "complete",
    "coverage": {
      "region": "eu-west",
      "start_inclusive": "2026-11-06T04:00:00Z",
      "end_exclusive": "2026-11-06T04:10:00Z"
    },
    "records": 12840,
    "omissions": []
  },
  "scope": {
    "tenant_id": "tenant_acme_prod",
    "run_id": "run_incident_042"
  },
  "expires_at": "2026-11-07T04:40:00Z",
  "retrieval": {
    "resolver": "artifact.read.v1",
    "consistency": "pinned_snapshot",
    "selectors": ["record_range", "query"]
  }
}

Each field has a specific job:

FieldWhat it makes checkable
artifact_idWhether a later operation targets the original immutable result.
content_hashWhether the stored bytes match a protected expected digest.
tool_call_idWhich protected producer record supplies tool, arguments, version, and outcome lineage.
schema_versionWhich payload interpretation and validation rules apply.
created_atWhen the stored artifact was created.
source_versionWhich source observation was captured and when it was observed.
completenessWhich bounded coverage was captured and what was omitted.
scopeWhich tenant and run own the artifact, checked against service state.
expires_atThe declared availability deadline, independent of evidence freshness.
retrievalWhich versioned resolver, consistency rules, and selectors apply.

The JSON is a description, not an enforcement mechanism. The service must bind it to protected metadata. Otherwise an agent could rewrite a tenant label, replace both the payload and its digest, or declare a partial capture complete.

Publish the reference only after the object and manifest are committed. Reacquisition or transformation creates a new identity. A changed user-facing filename need not matter if the resolver still pins the original object version.

Hash semantics also need precision. Hash exact stored bytes, or define a versioned canonical encoding. Do not hash one serialization and verify another. A whole-object digest can support service-side verification before slicing; it does not independently authenticate a detached excerpt. Chunk verification needs an appropriate authenticated structure and proofs.

“No matches” needs a boundary

Suppose the agent searches the snapshot for critical incidents and gets an empty result. There are several possible explanations:

  • All captured records were searched and none matched.
  • Only the first page was searched.
  • The query timed out before examining relevant records.
  • The capture omitted a region where the incident occurred.
  • Redaction removed fields required for the predicate.

Returning only [] hides these distinctions.

A selective-read response should identify the immutable artifact, source snapshot, exact range or normalized query, stable ordering, coverage examined, returned count, completion status, and whether more data remains. Its continuation cursor should bind those choices so the next page cannot silently switch datasets.

Capture completeness, scan completion, and prompt admission are separate facts. A complete scan of an incomplete capture still leaves missing evidence. A complete capture can produce a truncated query response. A complete response can then be omitted from the model’s context because of a token budget.

The strongest justified conclusion is bounded: “No critical events were found in this captured region and interval after a completed scan.” It says nothing about uncaptured regions or later events.

A remembered reference must not grant access

An agent can remember a reference longer than its permission lasts. A run might resume after a role changes, a document becomes restricted, or a tenant revokes sharing.

Recheck current authority on every disclosure, including cache hits and later pages. Ownership labels in the descriptor help identify the expected scope; they do not grant cross-run or cross-tenant access. Passing the identifier to another agent must not transfer authority automatically.

This becomes especially important in a persistent execution environment. Once arbitrary code has a direct reference to an unrestricted object, a separate read API cannot reliably mediate future access. The execution boundary needs controlled handles, isolation, and a way to invalidate access when permission changes. Merely telling the model to respect a label cannot supply those controls.

Derived copies also matter. A revoked source can survive in a printed excerpt, dataframe, summary, query cache, or export. Retention and deletion design must inventory those copies and report propagation status. Deleting the primary artifact cannot retract information already disclosed.

Persistence is different from immutable identity

A persistent Python scope preserves useful working state across turns. It can also contain a variable rebound to a new result or an object mutated in place. A familiar name therefore does not identify an immutable observation.

An implementation can freeze a snapshot or serialize a defined immutable representation before registering an artifact. If a handle depends on live kernel state, bind it to the kernel generation. After a reset, return an explicit unavailable outcome instead of pretending the old object survives.

A derived computation should preserve its input references and transformation lineage. A filtered table and its source are related artifacts, but they are different byte sequences with different coverage. Reusing the source hash for the filtered result would erase that distinction.

The same reasoning applies to files. Persistence provides storage lifetime; immutable identity provides stable meaning. A dependable retrieval design needs both, plus an honest statement of recovery limits.

Missing evidence changes what the agent may do

Return to the incident agent. Three cases require different recovery behavior.

The reference is intact but stale. If the task permits current observations and the run still has authority and budget, fetch a fresh snapshot. Give it a new reference and reassess the decision. If the task asks what happened at a particular historical instant, a new live capture cannot replace the missing historical evidence.

The result is partial. Suppose collection failed in one required region. Searching the available records may help investigation, but it cannot satisfy an evidence requirement covering all affected regions. Preserve the omitted region and the failure reason. Resume only if the source supports a consistent continuation; otherwise acquire a new bounded capture.

The reread fails. The object may have expired, been deleted, become inaccessible, or been lost with a kernel reset. Use bounded retries only when the failure and policy allow them. If required evidence remains unavailable, defer the dependent action. An old preview cannot silently substitute for the failed read.

Optional evidence can support a qualified answer when the decision’s requirements allow one. Required evidence needs an explicit gate. That distinction should be enforced by the runtime rather than left to the model’s confidence.

Fit the design around existing ContextOS boundaries

ContextOS already documents provenance-bearing context, explicit budget omissions, data_only treatment for retrieved material, and evidence requirements that must be satisfied before commit. Artifact retrieval should feed those existing mechanisms. It must not turn a verified file into instruction authority. Context Pack admission and gates.

This proposal does not change ToolResultEnvelope.artifacts, which remains an array of strings, or the existing attachment and evidence types. An adapter-owned resolver can recover a descriptor behind an opaque reference, verify the result, and supply structured evidence to the compiler. The detailed reference design specifies that mapping, proposed outcomes, and operational limits.

Before relying on such a service, test the boundaries directly: replace a backing object between verification and selection, revoke permission between pages, interrupt a scan, reuse a cursor against another snapshot, reset the kernel, and exhaust the recovery budget. The acceptance evidence should show both useful retrieval and visible refusal or deferral when the contract cannot be met.

The benefit of offloading is that the model can carry less while recovering what matters. That benefit depends on recovering the intended observation with its limits intact. The engineering work continues after the bytes leave the prompt.

Found this useful? Share it.

Share:XBSMRedditHNEmail

Continue through the same topic without returning to the index.

View the series