Skip to content

Artifacts and Sessions

The Python API exposes the same artifact policy as > artifacts: and an explicit session boundary for calls that must share conversation history.

Configure Artifact Handling

Use a mapping for concise configuration:

import kedi

kedi.configure(
    adapter="pydantic",
    artifacts={
        "enabled": True,
        "threshold": "100kb",
        "ttl": "1h",
        "store": "memory",
    },
)

Artifact handling is enabled by default. artifacts=False explicitly disables the inherited policy in configure(), context(), query(), or bind().

For a typed policy object:

from kedi import ArtifactPolicy

policy = ArtifactPolicy.patch(
    {
        "enabled": True,
        "store": "file",
        "path": ".kedi/artifacts",
        "threshold": "64kb",
        "ttl": "30m",
    }
)

kedi.configure(artifacts=policy)

Mappings use DSL field names such as threshold, ttl, idle_ttl, session_quota, and cleanup_interval. A normalized ArtifactPolicy exposes their internal byte/second forms as threshold_bytes, ttl_seconds, idle_ttl_seconds, session_quota_bytes, and cleanup_interval_seconds.

Per-Callable and Scoped Overrides

Artifact configuration is accepted by configure, context, query, and bind:

import kedi


@kedi.query(artifacts={"enabled": True, "threshold": "32kb"})
def create_report(topic: str) -> str:
    """kedi
    >> A detailed report about <topic> is [report].
    = `report`
    """
    ...


with kedi.context(artifacts=False):
    report = create_report("typed orchestration")

An artifact-backed result still returns as the original annotated Python value. ArtifactRef is model-visible transport metadata, not a replacement return type for ordinary application code.

Stateful Sessions

Kedi is stateless unless a ConversationState is supplied. session() creates or activates one state and closes its artifact manager on exit:

import kedi

kedi.configure(
    adapter="pydantic",
    artifacts={"enabled": True, "threshold": "100kb"},
)

with kedi.session() as conversation:
    first = create_report("release readiness")
    second = review_report()

Use the async form in asynchronous code:

async with kedi.session() as conversation:
    first = await create_report_async("release readiness")
    second = await review_report_async()

An existing open ConversationState may be supplied when the caller owns its lifecycle:

from kedi import ConversationState

state = ConversationState()

with kedi.session(state):
    first = create_report("runtime safety")
    second = review_report()

Exiting session() closes its artifact manager, so that state cannot then be resumed. The CLI does not create persistent conversation state implicitly.

For direct decorator control, query(..., conversation=state) and bind(..., conversation=state) use the same state without changing unrelated configuration contexts.

Public Artifact Types

These types are exported from kedi:

Type Role
ArtifactPolicy Validated policy and lexical overlay
ArtifactRef[T] Compact metadata sent across model context
ArtifactChunk Bounded result from an artifact read
ArtifactSearchResult Metadata-only search result
ArtifactReleaseResult Payload release status
ArtifactHandle[T] Internal lazy native-value handle
ConversationState Portable history and artifact ownership

Application code normally configures ArtifactPolicy and ConversationState. The remaining types are useful for custom adapters, tooling, and diagnostics.

See Tool Artifacts for storage guarantees, management tools, expiry, quotas, and cache-epoch history semantics.