Advanced
Runtime boundaries
Separate clients, servers, workers, tools, and model calls.
Anvia is designed around explicit runtime boundaries. The core package provides provider-neutral primitives. Other packages adapt providers, transports, stores, tools, and observability systems.
Good boundaries make agents easier to test and safer to deploy. They also keep provider SDKs, database clients, secrets, and product permissions out of places they do not belong.
Package Boundaries
@anvia/core contains the runtime contracts. Provider packages such as @anvia/openai, @anvia/anthropic, @anvia/gemini, and @anvia/mistral turn provider SDKs into Anvia models.
Embedding and vector packages adapt retrieval infrastructure. Observability packages connect runtime events to systems such as OpenTelemetry and Langfuse. @anvia/server and @anvia/react help move streams through app transports. Studio provides a local and internal runtime UI.
Most integration packages declare @anvia/core as a peer dependency. That keeps runtime contracts shared while letting provider SDKs and adapters evolve separately.
Runtime Object Boundaries
The provider client owns credentials, base URLs, headers, and SDK setup. A model is the reusable provider capability created from that client. An agent adds instructions, tools, context, hooks, observers, memory, and limits. A session supplies the durable memory context for conversation history. A prompt request carries the current input, trace metadata, and one-off overrides.
Create these objects in startup code, factories, tests, jobs, or request handlers. Anvia does not require a global registry, and you should not need one to make agents discoverable inside your app.
Dependency Injection Shape
Anvia’s runtime boundaries are meant to be dependency-injection friendly. Provider clients
become model objects before core sees them. Memory is a MemoryStore passed into an
agent. Retrieval is a vector index passed into dynamic context or a tool. Observability is
an observer passed into AgentBuilder.observe(...). Product services are called from
tools or runners, not hidden behind prompt text.
This keeps framework ownership narrow. Anvia owns the agent loop, tool execution, streaming events, hooks, middleware, approvals, and runtime contracts. Your application owns the concrete services, storage systems, permissions, transports, deployment, and product response shape.
Server, Worker, And Browser Boundaries
Keep provider clients, API keys, file loaders, PDF loaders, vector-store clients, and side-effect tools on the server or in workers.
Browser code should receive only product-safe outputs or streams. A React UI can submit a message to your app route, and that route can call an Anvia runner. The browser does not need provider credentials, vector-store clients, or privileged tool implementations.
Workers are useful for long-running pipelines, ingestion, evals, and retried jobs. In those cases, the route should enqueue work and the worker should own the Anvia run. That keeps user-facing latency separate from provider latency, retries, and downstream service failures.
Long-Running Work
Do not force every agent run into a request-response route. Some workflows should become jobs:
- document ingestion and embedding
- research pipelines with many model calls
- nightly eval suites
- bulk extraction
- approval workflows that may wait on a human
For these workflows, store a job id and status in your app database. The worker can emit events, write trace metadata, persist intermediate outputs, and retry safe steps. The user-facing route can poll or subscribe to job status without holding a provider request open.
Studio Boundary
Studio is useful for local development and internal operations. Treat it as a runtime inspection surface, not as your product authorization layer.
Your app still owns product user authentication, reviewer permissions for approvals, production storage policy, deployment, network access, user-facing UI, and response shape. Studio can help inspect sessions, traces, tools, and registered agents, but it should not become the only place where production permissions are enforced.
Practical Rule
When a dependency reaches outside the process, make the boundary explicit. Provider SDKs, databases, queues, object stores, vector stores, and tracing systems should be injected into runners, factories, tools, or adapters instead of hidden inside prompt text.
If a module cannot run in a unit test without real secrets, it is probably doing too much. Split provider setup, product services, agent construction, and runner logic until each piece has a clear test seam.
Review Questions
Before shipping a runtime boundary, ask:
- Can the route be tested without a provider call?
- Can tools be tested without the agent?
- Can the agent be registered in Studio without production secrets?
- Can browser code render the stream without seeing private tool results?
- Can a worker resume or fail a long-running run without losing audit detail?
If the answer is no, the boundary is probably still too implicit.
