PR #309 · pramaan-io/pramaan-functions · merged 2026-06-12
Two services. Two copies of every type. One silent drift between them.
What breaks when the HTTP layer and the brain each keep their own private dictionary?
Adding one field becomes a cross-repo release.
The fix — Same word, same meaning — across the broker and the brain.
sequenceDiagram autonumber participant broker as Broker (HTTP layer) participant brain as Brain (Atlas agent) broker->>broker: 1. Mint run identity + one-shot grant broker->>brain: 2. Hand over the invoke form brain->>brain: 3. Run the agent brain->>broker: 4. Stream events as numbered ledger lines broker->>broker: 5. parse_event_line — halt on unknown brain->>brain: 6. HITL pause on RunBlocked broker-->>brain: 7. Resume with same grant (one shot) brain->>brain: 8. Reducer folds to terminal + price brain->>broker: 9. Terminal event or failure envelope
| Method | in → out | what it does |
|---|---|---|
mark_failure_context | (error, failure_stage, failure_kind, failed_component) → BaseException | |
build_failure_envelope | (error, run_id, firm_id, matter_id, failure_stage, failed_component, created_at) → dict[str, Any] | |
failure_event_payload | (error, envelope) → dict[str, Any] |
Builds the canonical failure envelope; classifies exceptions by kind and stage so broker and brain share one diagnosis. Relocated from the rails.
| new method | signature |
|---|---|
mark_failure_context | (error, failure_stage, failure_kind, failed_component) → BaseException |
build_failure_envelope | (error, run_id, firm_id, matter_id, failure_stage, failed_component, created_at) → dict[str, Any] |
failure_event_payload | (error, envelope) → dict[str, Any] |
_classify_kind | (error, stage) → str |
_sanitized_summary | (kind, stage) → str |
_recovery_recommendation | (kind, stage) → str |
_user_visible_message | (kind, stage) → str |
_is_retryable | (kind) → bool |
_retry_after_seconds | (kind) → int |
_internal_debug_ref | (raw_error_class, raw_message) → str |
_context_value | (error, name) → str | None |
_valid_kind | (value) → str |
_valid_stage | (value) → str |
_default_component | (stage) → str |
Defines eight event types as a Pydantic discriminated union and parse_event_line rejecting unknown schemas. One source of truth for the agent vocabulary.
| new class | signature |
|---|---|
Usage | (class) |
RunStartedPayload | (class) |
TurnDeltaPayload | (class) |
TurnCompletedPayload | (class) |
ModelUsagePayload | (class) |
ToolRequestedPayload | (class) |
BlockApproval | (class) |
RunBlockedPayload | (class) |
RunCompletedPayload | (class) |
RunFailedPayload | (class) |
_EventBase | (class) |
RunStartedEvent | (class) |
TurnDeltaEvent | (class) |
TurnCompletedEvent | (class) |
ModelUsageEvent | (class) |
ToolRequestedEvent | (class) |
RunBlockedEvent | (class) |
RunCompletedEvent | (class) |
RunFailedEvent | (class) |
parse_event_line | (line) → AgentStreamEvent |
input_tokens : intoutput_tokens : intmodel_id : strprompt_version : strschema_version : strusage : Usagetool_name : strinput_sha256 : strtool_input_hash : strrisk_tier : strreason : strhuman_summary : strapproval : BlockApprovalstop_reason : strerror_class : strerror_message : strfailure_stage : str | Nonefailure_kind : str | Nonerun_id : strpayload : RunFailedPayload_event_adapter : TypeAdapter[AgentStreamEvent]Folds an event stream into a terminal run state with immutability, HITL hold/release, and cost-abort. Relocated verbatim from the consumer side.
| new method | signature |
|---|---|
reduce_agent_run | (events) → dict[str, Any] |
_run_failed_status | (payload) → str |
Defines HITL risk-tier types and resolves a tool to a risk decision. Fail-closed default denies any unlisted tool rather than auto-approving.
| new class | signature |
|---|---|
ToolRiskTier | (class) |
ToolRiskPolicyEntry | (tier, reason, ToolRiskDecision, tool_name, matched_policy) |
ToolRiskPolicy | (version, default, tools) |
get_tool_risk_decision | (tool_name, metadata) → ToolRiskDecision |
load_hitl_risk_policy | () → ToolRiskPolicy |
_parse_entry | (raw_entry, policy_key) → ToolRiskPolicyEntry |
_non_empty_tool_name | (tool_name) → str |
Defines the broker-to-brain AgentInvoke envelope: InvokeMeta set by the broker, plus an optional one-shot ApprovalGrant bound to a single tool input hash.
| new class | signature |
|---|---|
ApprovalGrant | (class) |
InvokeMeta | (class) |
HistoryMessage | (class) |
AgentInvoke | (class) |
approval_request_id : UUIDtool_name : strtool_input_hash : strrun_id : UUIDfirm_id : UUIDuser_id : UUIDcorrelation_id : str | Noneform_id : str | Nonematter_id : UUID | Nonechat_session_id : UUID | Noneapproval : ApprovalGrant | Nonerole : strtext : stragent_key : strmode : strmeta : InvokeMetacounsel_message : str | NoneConcrete fail-closed policy listing known tools and their risk reasons; default section denies any tool not named.
reason : Irreversible external court filing that must not run without human approval.Per-model Bedrock pricing in USD per token, relocated from Atlas config. Feeds the cost cap with the real model rates.
| new method | signature |
|---|---|
token_cost_usd | (model_id, input_tokens, output_tokens) → float |
ContractModel base class for every Pydantic contract in the package; one config for extra-field handling, serialization, and validation behavior across all contracts.
| new class | signature |
|---|---|
ContractModel | (class) |