Artifacts¶
Tool Artifacts is Kedi's bounded large-value transport. It prevents large tool results and generated fields from being copied into model context while preserving the original typed value for Kedi and embedded Python.
Artifacts are enabled by default. They are part of the normal agent execution contract, not an optional persistence API: values that remain small continue to flow inline, while qualifying values are represented to the model by compact, session-scoped references.
Normative Model¶
Tool Artifacts separates one logical value into three representations:
- Native value: the original
str,bytes, list, Pydantic model, dataclass, or other Python object used by Kedi and Python. - Stored payload: the serialized or process-local value owned by one
ArtifactManagerand one artifact session. - Model-visible reference: a bounded
ArtifactRefcontaining metadata, summary, preview, size, expiry, and instructions for retrieving content.
These representations have different consumers and must not be conflated:
| Consumer | Representation |
|---|---|
Kedi return block, embedded Python, run_main() |
Original native value |
| A later model call receiving an artifact-backed substitution | ArtifactRef |
read_artifact and run_artifact_code |
Bounded views of the stored payload |
| Portable conversation history | References and bounded read results |
The core invariant is:
Artifact conversion may change how a value crosses the model boundary, but it must not change the value observed by Kedi or Python.
Consequently, ArtifactRef[T] is a model transport type. It does not replace
T in ordinary application code.
Runtime Architecture¶
One artifact-enabled execution is composed of the following parts:
| Component | Responsibility |
|---|---|
ArtifactPolicy |
Lexically scoped admission, storage, quota, and expiry configuration |
ArtifactManager |
Session ownership, admission, deduplication, reads, leases, release, and cleanup |
ArtifactStore |
Memory or file-backed payload storage |
ArtifactHandle[T] |
Lazy internal binding that resolves to the native T |
ArtifactRef[T] |
Compact model-visible metadata |
| Artifact management tools | Search, bounded read, code-based reduction, and release |
ArtifactHistory |
Append-only lifecycle events for portable history and telemetry |
The manager belongs to an explicit artifact session. A normal stateless Kedi
run creates a session for that run. A Python session() keeps one manager and
conversation state across multiple calls.
The management tools and artifact instructions are installed as a stable contract from the first artifact-enabled model call. They are not injected only after the first large result. Keeping the prefix stable avoids invalidating provider prompt caches when an artifact first appears later in a run.
End-to-End Dataflow¶
Generated fields¶
Each generated field is validated against its declared Kedi type before artifact admission. Fields are measured independently; one large field can become an artifact while sibling fields remain inline.
model output
-> structured-output validation
-> serialize and measure each field
-> inline value OR ArtifactHandle[T]
-> bind into KediEnv
Tool results¶
A tool result enters artifact admission only after the tool was approved, executed, and return-validated:
tool request
-> approval
-> tool execution
-> return validation
-> serialize and measure
-> inline result OR ArtifactHandle[T]
-> model receives inline result OR ArtifactRef[T]
An ArtifactRef returned from a tool means the source tool already completed.
The model must inspect the reference instead of repeating the source operation.
Native reads¶
Kedi stores an ArtifactHandle[T] internally. When Kedi or embedded Python
reads that binding, the handle asks its session manager for the original value:
> artifacts:
threshold: 1b
>> A detailed explanation of Kedi is [report].
# `report` resolves to the complete native string here.
= `report.upper()`
The same rule applies to run_main(), @kedi.query, and @kedi.bind: their
callers receive the native result, not artifact metadata.
Model substitutions¶
The model boundary is deliberately different. A later template that receives an artifact-backed value sees only its compact reference:
>> A detailed release report is [report].
>> The conclusion in <report> is [conclusion].
The second call can use read_artifact or run_artifact_code to retrieve only
the evidence required to fill conclusion. The full report is not implicitly
copied into the second prompt.
Admission Algorithm¶
See Admission Algorithm.
Configuration and Lexical Scope¶
See Configuration and Lexical Scope.
Policy reference¶
See Configuration and Lexical Scope.
Reference Contract¶
See Reference Contract.
Management Tools¶
See Management Tools.
search_artifacts¶
See Management Tools.
read_artifact¶
See Management Tools.
query_artifact (opt-in)¶
See Management Tools.
run_artifact_code¶
See Management Tools.
release_artifact¶
See Management Tools.
Agent Routing Contract¶
End-to-End Multi-Artifact Reduction¶
See End-to-End Multi-Artifact Reduction.
Explicit Streaming¶
See Explicit Streaming.
Serialization and Stores¶
Canonical serialization¶
Memory store¶
File store¶
Quotas, Expiry, and Concurrency¶
See Quotas, Expiry, and Concurrency.
History and Cache Stability¶
See History and Cache Stability.
Failure Semantics¶
See Failure Semantics.
Adapter Contract¶
Artifact support and conversation continuation are separate contracts. Consult the adapter extension contract and the selected adapter's documentation instead of inferring history support from artifact support. Pydantic AI and LangChain both support stateful conversations.
Security and Observability¶
See Security and Observability.
Operational Guidance¶
See Operational Guidance.