Data Models
The typed shapes you read off responses and pass in - SessionResponse, RawSSEEvent, TokenUsage, the privacy models, and billing/usage models.
#Shared Data Models
The typed Pydantic shapes you construct as agent input (messages, private-data descriptors) and read back as agent output (response objects, event streams, token counts), shared across the mAIvn libraries.
These are the structural counterpart to the maivn SDK docs: that reference describes behavior (how to build, invoke, and stream an agent), while this page describes the shapes that behavior produces and consumes.
Note Most of these models are importable frommaivn,maivn.messages, ormaivn.events, as shown in each section. Token usage is exposed as a dictionary onInvokeResponse, not as a public model.
#InvokeResponse and StreamEvent
These are the two shapes an invocation hands back.
#InvokeResponse
Agent.invoke(), Agent.ainvoke(), Swarm.invoke(), and Swarm.ainvoke() all return a single InvokeResponse. It is the canonical "what happened in this turn" object.
from maivn import Agent
from maivn.messages import HumanMessage
agent = Agent(name='assistant', api_key='...')
response = agent.invoke([HumanMessage(content='Summarize this ticket.')])
print(response.response) # final assistant text
print(response.result) # structured / final-tool output, when applicable
print(response.stop_reason)responsevs.resultresponseis the human-readable answer.resultis machine-readable output, populated when you force a final tool or request structured output. A typical text turn fillsresponseand leavesresultasNone; a structured-output turn fills both.
from pydantic import BaseModel
class Summary(BaseModel):
title: str
bullets: list[str]
response = agent.structured_output(Summary).invoke(
[HumanMessage(content='Summarize this ticket.')]
)
summary = response.result # a typed Summary instance
print(summary.title, summary.bullets)#StreamEvent
Agent.stream() and Swarm.stream() yield maivn.StreamEvent. It retains the canonical event envelope (position, event_type, and data) and exposes compatibility name and payload properties for common event handling.
from maivn import StreamEvent
event = StreamEvent(position=0, event_type="run.started", data={})
print(event.position, event.event_type, event.data)You can read it directly when you just need the raw stream:
for event in agent.stream([HumanMessage(content='Think through this.')]):
if event.name == 'system_tool_chunk':
print(event.payload.get('text', ''), end='')
elif event.name == 'final':
print('\nDone')Tip For product integrations, adapt eachStreamEventtoRawSSEEvent(name=event.name, payload=event.payload)and normalize once withmaivn.events.normalize_stream(...). The result is a descriptor-richAppEventstream.
#Token usage
InvokeResponse.token_usage is a normalized dictionary derived from response.usage. It is None when neither input nor output counts are present.
usage = response.token_usage
if usage is not None:
print(usage['total_tokens'], 'total')
print(usage['input_tokens'], 'in /', usage['output_tokens'], 'out')All values in the normalized dictionary are integers. total_tokens is currently input_tokens + output_tokens; cache and reasoning counters remain separately available.
No cost by design Per-run usage carries token counts only. The billing models below validate aggregated data obtained through an authorized application integration; the public Client does not fetch it.#Public Billing / Usage Models
These models describe an organization's plan and usage for a billing period. Every model is importable from maivn and ignores unknown fields, so it can validate extensible payloads obtained outside the current public client surface.
BillingUsage represents a single account-level usage snapshot:
The nested shapes:
BillingPlan—name,display_name,tier.BillingCurrentUsage—tokens_used,tokens_used_raw,tokens_limit,requests_used,requests_limit,storage_used,storage_limit. A limit of-1means unlimited.BillingUsageBreakdown—organization_id,period_start,period_end,totals(aBillingUsageTotals), andprojects(a list ofBillingUsageProject).BillingUsageTotals—billed_tokens,raw_tokens,requests.BillingUsageProject—project_id(Nonefor the unattributed bucket),project_name,billed_tokens,raw_tokens,requests, andapi_keys(a list ofBillingUsageApiKey).BillingUsageApiKey—api_key_id(Nonefor the "Unknown API key" bucket),api_key_name,billed_tokens,raw_tokens,requests.
from maivn import BillingUsage
usage = BillingUsage.model_validate(usage_payload)
print(usage.plan.tier if usage.plan else 'no plan')
print(f'{usage.usage.tokens_used:,} / {usage.usage.tokens_limit:,} tokens')The current public Client has no get_usage() transport method. See the billing-model reference for the supported read-model boundary.
#Privacy Models
These shapes let you declare sensitive data so it is handled safely rather than passed to the model in cleartext. The conceptual model is: the LLM plans against a schema (field names, types, and labels), and real values are injected into tools only at execution time. The companion behavior (how to attach private_data to an agent and inject values into tools) lives in the Private Data guide. This section covers the shapes you construct.
Controls, not certifications. These are technical privacy controls, not certifications. mAIvn holds no SOC 2, HIPAA, ISO 27001, or FedRAMP certification. phi_mode limits HIPAA Safe Harbor whitelist categories; it does not make a deployment HIPAA-compliant, provide a BAA, or replace required audits and organizational controls. Evaluate and use these controls at your own risk under the mAIvn Platform Disclaimer.Import them from the SDK:
from maivn.messages import RedactedMessage, PrivateData
from maivn import PIIWhitelist, PIIWhitelistEntry, HIPAA_SAFE_HARBOR_CATEGORIES#PrivateData
A structured descriptor for a known sensitive value. It enriches the schema the model sees with a custom key name, type, and label, without ever exposing the value itself to the model by default.
PrivateData(
value: object, # the actual sensitive value (required)
name: str | None = None, # custom placeholder key, e.g. 'patient_name'
pii_type: str | None = None, # entity type: 'person', 'phone', 'email', 'date', ...
label: str | None = None, # human-readable label shown in the schema
description: str | None = None, # extra context for the model
format: str | None = None, # semantic format hint: 'email', 'phone', 'date', ...
)In RedactedMessage.known_pii_values, descriptors retain their metadata and declared names receive user_ placeholder keys. A scope's private_data list normalizes descriptors to their names and values only; it discards labels, entity types, descriptions, and format hints. Use a redacted message when that metadata needs to reach the runtime.
agent = Agent(
name='intake',
api_key='...',
private_data=[
PrivateData(value='Maria Santos', name='patient_name', pii_type='person',
label='Patient Name'),
PrivateData(value='MEM-882441', name='member_id', label='Member ID'),
],
)#RedactedMessage
A message type that triggers automatic PII detection on the user-supplied text. Send one instead of a HumanMessage when the input may contain sensitive values you want detected and redacted before any model-visible context is built.
RedactedMessage(
content: str | list[ContentBlock],
known_pii_values: list[str | PrivateData] | None = None,
pii_whitelist: PIIWhitelist | None = None,
attachments: list[Attachment] | None = None,
metadata: dict[str, MetadataValue] | None = None,
message_id: str = ...,
ts: str = ...,
)from maivn.messages import RedactedMessage
response = agent.invoke([
RedactedMessage(content='My email is john@example.com and SSN is 123-45-6789.')
])Use known_pii_values to declare values explicitly (raw strings or PrivateData descriptors) so they are scrubbed even if auto-detection does not catch them. The runtime detects common identifier categories (email, phone, SSN, credit card, IBAN/SWIFT, medical record numbers, VINs, and named entities such as person, location, date, IP, and URL), each paired with a structural validator to avoid flagging look-alikes like order numbers.
#PIIWhitelist and PIIWhitelistEntry
Configuration for leaving approved spans in cleartext. The whitelist is evaluated after detection (so the value is still recorded as having been present) but before the value would be registered as private, so the matched span passes through.
PIIWhitelist(
entries: tuple[PIIWhitelistEntry, ...] = (),
phi_mode: bool = False,
)
PIIWhitelistEntry(
entity_type: str | None = None, # one-of: a whole category
pattern: str | None = None, # one-of: a regex
value: str | None = None, # one-of: a literal value
justification: str = ..., # required, >= 8 characters
label: str | None = None,
)Each entry matches by one of entity_type, pattern, or value, and every entry requires a justification of at least 8 characters. Setting phi_mode=True refuses entity_type entries for any HIPAA Safe Harbor category at construction (raising ValueError). Use a specific value or pattern for individually approved instances instead. Both models are frozen (immutable after construction).
whitelist = PIIWhitelist(
entries=(
PIIWhitelistEntry(
entity_type='url',
justification='Public marketing URLs needed for citations.',
),
PIIWhitelistEntry(
value='support@maivn.io',
justification='Public support address listed on the docs site.',
),
),
)
message = RedactedMessage(
content='See https://maivn.io and email support@maivn.io',
pii_whitelist=whitelist,
)#HIPAA_SAFE_HARBOR_CATEGORIES
An exported constant: a frozenset of the canonical entity-type names that phi_mode=True blocks from entity_type whitelisting. Use it to validate your own policy before constructing a PIIWhitelist.
from maivn import HIPAA_SAFE_HARBOR_CATEGORIES
if 'person' in HIPAA_SAFE_HARBOR_CATEGORIES:
# ... avoid a category-wide whitelist for names under phi_mode
...#Message Types
Messages are how you talk to an agent and how it talks back. They live in maivn.messages and are the input shapes for every invoke() / stream() call.
from maivn.messages import HumanMessage, AIMessage, SystemMessagefrom maivn.messages import SystemMessage, HumanMessage
messages = [
SystemMessage(content='You are a concise Python expert.'),
HumanMessage(content='How do I read a file?'),
]
response = agent.invoke(messages)If you set system_prompt on the Agent constructor and your messages do not include a SystemMessage, one is injected automatically. RedactedMessage (above) is the privacy-aware sibling of HumanMessage. For the full message surface (attachments, multi-turn patterns, and BaseMessage for type hints), see the Messages reference.
#See Also
- SDK Reference — the behavioral surface:
Agent,Swarm, tools, events, scheduling. - Messages reference — full message and privacy-model details, attachments, and patterns.
- Private Data guide — how the schema-only planning and runtime-injection model works end to end.
- Billing models — supported read models and the deliberately absent client transport.
- Events reference — normalizing the raw stream into the
AppEventcontract for frontends.