dharta-runtime 0.6.77__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. dharta/__init__.py +46 -0
  2. dharta/__main__.py +4 -0
  3. dharta/active_releases.py +243 -0
  4. dharta/agent.py +59 -0
  5. dharta/agent_builder_surface_authority.py +326 -0
  6. dharta/agent_runtime.py +290 -0
  7. dharta/app.py +757 -0
  8. dharta/artifacts/__init__.py +227 -0
  9. dharta/artifacts/agent_activation.py +146 -0
  10. dharta/artifacts/agent_activation_authority.py +204 -0
  11. dharta/artifacts/agent_activation_transport.py +148 -0
  12. dharta/artifacts/agent_delegation_contract.py +284 -0
  13. dharta/artifacts/agent_package.py +74 -0
  14. dharta/artifacts/agentcore_renderer_backend.py +1284 -0
  15. dharta/artifacts/artifact-runtime.json +750 -0
  16. dharta/artifacts/builtin_runner.py +230 -0
  17. dharta/artifacts/builtin_views.py +181 -0
  18. dharta/artifacts/cli.py +391 -0
  19. dharta/artifacts/contract.py +328 -0
  20. dharta/artifacts/contract_generated.py +204 -0
  21. dharta/artifacts/executable_ingest.py +305 -0
  22. dharta/artifacts/executable_models.py +202 -0
  23. dharta/artifacts/execution_coordinator.py +109 -0
  24. dharta/artifacts/execution_cost.py +77 -0
  25. dharta/artifacts/execution_materializer.py +351 -0
  26. dharta/artifacts/execution_service.py +118 -0
  27. dharta/artifacts/grounded.py +108 -0
  28. dharta/artifacts/helper.py +326 -0
  29. dharta/artifacts/http_gateway.py +525 -0
  30. dharta/artifacts/index.py +246 -0
  31. dharta/artifacts/ingest.py +492 -0
  32. dharta/artifacts/injection.py +85 -0
  33. dharta/artifacts/legacy_adapter.py +84 -0
  34. dharta/artifacts/manifest.py +193 -0
  35. dharta/artifacts/manifest_store.py +208 -0
  36. dharta/artifacts/pack_export.py +408 -0
  37. dharta/artifacts/portable_execution_pack.py +255 -0
  38. dharta/artifacts/portable_pack_codec.py +206 -0
  39. dharta/artifacts/portable_pack_contract.py +224 -0
  40. dharta/artifacts/portable_pack_files.py +352 -0
  41. dharta/artifacts/portable_share_runtime.py +42 -0
  42. dharta/artifacts/portable_share_service.py +61 -0
  43. dharta/artifacts/presentation.py +209 -0
  44. dharta/artifacts/records.py +395 -0
  45. dharta/artifacts/release_context.py +68 -0
  46. dharta/artifacts/runner_cli.py +116 -0
  47. dharta/artifacts/runner_supervisor.py +789 -0
  48. dharta/artifacts/s3_posix_tree.py +716 -0
  49. dharta/artifacts/share_pack.py +729 -0
  50. dharta/artifacts/share_retention.py +77 -0
  51. dharta/artifacts/skill/SKILL.md +232 -0
  52. dharta/artifacts/snapshot_coordinator.py +180 -0
  53. dharta/artifacts/supervisor_transport.py +110 -0
  54. dharta/artifacts/tree_resolver.py +457 -0
  55. dharta/artifacts/types.py +244 -0
  56. dharta/billing/__init__.py +23 -0
  57. dharta/billing/agentcore_resource_aggregation.py +246 -0
  58. dharta/billing/agentcore_resource_collector.py +639 -0
  59. dharta/billing/agentcore_resource_gaps.py +313 -0
  60. dharta/billing/agentcore_resource_schema.py +148 -0
  61. dharta/billing/agentcore_resource_store.py +317 -0
  62. dharta/billing/agentcore_usage_delivery.py +221 -0
  63. dharta/billing/agentcore_usage_logs.py +238 -0
  64. dharta/billing/invocation_emitter.py +483 -0
  65. dharta/billing/telemetry_event_contract.py +282 -0
  66. dharta/billing/telemetry_identity.py +53 -0
  67. dharta/billing/telemetry_microvm_bindings.py +142 -0
  68. dharta/billing/telemetry_outbox.py +442 -0
  69. dharta/billing/telemetry_outbox_schema.py +71 -0
  70. dharta/billing/turn_admission.py +349 -0
  71. dharta/billing/turn_payload_contract.py +160 -0
  72. dharta/billing/usage_emitter.py +794 -0
  73. dharta/billing/usage_outbox.py +1461 -0
  74. dharta/billing/usage_outbox_schema.py +566 -0
  75. dharta/browser_url_policy.py +41 -0
  76. dharta/builder.py +222 -0
  77. dharta/byok.py +224 -0
  78. dharta/cache.py +257 -0
  79. dharta/capture_contract.py +88 -0
  80. dharta/cli.py +913 -0
  81. dharta/cli_renderer.py +248 -0
  82. dharta/connector.py +42 -0
  83. dharta/consumer/__init__.py +7 -0
  84. dharta/consumer/activity.py +708 -0
  85. dharta/consumer/agent_origins.py +98 -0
  86. dharta/consumer/challenge.py +116 -0
  87. dharta/consumer/context_envelope.py +231 -0
  88. dharta/consumer/embed.py +411 -0
  89. dharta/consumer/event_log.py +244 -0
  90. dharta/consumer/events.py +182 -0
  91. dharta/consumer/managed_agents.py +297 -0
  92. dharta/consumer/openai_chat.py +113 -0
  93. dharta/consumer/openai_responses.py +137 -0
  94. dharta/consumer/session_token.py +35 -0
  95. dharta/consumer/tasks.py +326 -0
  96. dharta/consumer/transcript.py +243 -0
  97. dharta/consumer/turn_projection.py +118 -0
  98. dharta/consumer/wire_events.py +91 -0
  99. dharta/control_plane.py +372 -0
  100. dharta/di/__init__.py +32 -0
  101. dharta/di/allocator.py +287 -0
  102. dharta/di/anchor.py +191 -0
  103. dharta/di/audit.py +91 -0
  104. dharta/di/bik.py +58 -0
  105. dharta/di/conversation.py +155 -0
  106. dharta/di/crypto.py +100 -0
  107. dharta/di/envelope.py +73 -0
  108. dharta/di/instance_token.py +86 -0
  109. dharta/di/keys.py +250 -0
  110. dharta/di/leak_guard.py +112 -0
  111. dharta/di/lifecycle.py +88 -0
  112. dharta/di/object_cipher.py +364 -0
  113. dharta/di/revocation.py +155 -0
  114. dharta/di/tenant.py +149 -0
  115. dharta/durable/__init__.py +22 -0
  116. dharta/durable/local.py +112 -0
  117. dharta/durable/port.py +24 -0
  118. dharta/durable/s3.py +117 -0
  119. dharta/end_user_context.py +239 -0
  120. dharta/env_policy.py +85 -0
  121. dharta/events.py +21 -0
  122. dharta/execution/__init__.py +24 -0
  123. dharta/execution/fake.py +78 -0
  124. dharta/execution/port.py +85 -0
  125. dharta/gateway/__init__.py +15 -0
  126. dharta/gateway/base.py +29 -0
  127. dharta/gateway/events.py +73 -0
  128. dharta/gateway/http.py +80 -0
  129. dharta/gateway/local.py +151 -0
  130. dharta/gateway/registry.py +65 -0
  131. dharta/genui/__init__.py +29 -0
  132. dharta/genui/bundle.py +179 -0
  133. dharta/genui/injection.py +87 -0
  134. dharta/genui/manifest.py +133 -0
  135. dharta/genui/skill/SKILL.md +114 -0
  136. dharta/harness/__init__.py +4 -0
  137. dharta/harness/account_mcp.py +189 -0
  138. dharta/harness/base.py +492 -0
  139. dharta/harness/claude.py +697 -0
  140. dharta/harness/claude_message_mapper.py +899 -0
  141. dharta/harness/claude_runtime.py +777 -0
  142. dharta/harness/claude_runtime_types.py +253 -0
  143. dharta/harness/codex.py +665 -0
  144. dharta/harness/config_env.py +101 -0
  145. dharta/harness/deepagents.py +750 -0
  146. dharta/harness/factory.py +91 -0
  147. dharta/harness/gateway_usage.py +84 -0
  148. dharta/harness/goose.py +767 -0
  149. dharta/harness/opencode.py +610 -0
  150. dharta/harness/platform_context.py +100 -0
  151. dharta/harness/spec.py +173 -0
  152. dharta/harness/stub.py +301 -0
  153. dharta/harness/subprocess.py +343 -0
  154. dharta/harness/utils.py +103 -0
  155. dharta/harness/wakeups_mcp.py +218 -0
  156. dharta/host_assets.py +64 -0
  157. dharta/instance.py +739 -0
  158. dharta/model_broker_quota_contracts.py +153 -0
  159. dharta/model_broker_transport_contracts/__init__.py +101 -0
  160. dharta/model_broker_transport_contracts/_common.py +239 -0
  161. dharta/model_broker_transport_contracts/binding.py +282 -0
  162. dharta/model_broker_transport_contracts/relay.py +320 -0
  163. dharta/model_broker_transport_contracts/request.py +642 -0
  164. dharta/model_broker_transport_contracts/spool.py +489 -0
  165. dharta/model_broker_transport_contracts/spool_reader.py +455 -0
  166. dharta/model_broker_transport_contracts/spool_sequence.py +188 -0
  167. dharta/model_broker_transport_contracts/verification.py +417 -0
  168. dharta/model_connector_adapter_registry.py +708 -0
  169. dharta/model_contracts.py +2483 -0
  170. dharta/model_egress_contracts/__init__.py +85 -0
  171. dharta/model_egress_contracts/_common.py +365 -0
  172. dharta/model_egress_contracts/bedrock_capability.py +699 -0
  173. dharta/model_egress_contracts/dispatch_authorization.py +383 -0
  174. dharta/model_egress_contracts/dispatch_context.py +146 -0
  175. dharta/model_egress_contracts/endpoint_policy.py +488 -0
  176. dharta/model_egress_contracts/exact_grant.py +652 -0
  177. dharta/model_egress_contracts/manifest.py +878 -0
  178. dharta/model_egress_contracts/manifest_verification.py +290 -0
  179. dharta/model_endpoint_policy.py +95 -0
  180. dharta/model_failure.py +248 -0
  181. dharta/model_gateway.py +1745 -0
  182. dharta/model_http_transport.py +106 -0
  183. dharta/model_readiness.py +348 -0
  184. dharta/model_readiness_credentials.py +199 -0
  185. dharta/model_route.py +867 -0
  186. dharta/model_settings.py +691 -0
  187. dharta/observability/__init__.py +172 -0
  188. dharta/observability/_noop.py +75 -0
  189. dharta/observability/_otel.py +104 -0
  190. dharta/observability/attribute_policy.py +217 -0
  191. dharta/observability/gen_ai_emitter.py +547 -0
  192. dharta/observability/gen_ai_semconv.py +76 -0
  193. dharta/observability/log_metric_policy.py +132 -0
  194. dharta/observability/logging_setup.py +100 -0
  195. dharta/observability/metrics.py +107 -0
  196. dharta/observability/secret_redaction.py +96 -0
  197. dharta/observability/sentry.py +154 -0
  198. dharta/observability/stream_event_contract.py +87 -0
  199. dharta/observability/trace_propagation.py +88 -0
  200. dharta/participant.py +55 -0
  201. dharta/persistence/__init__.py +44 -0
  202. dharta/persistence/encrypting_backend.py +44 -0
  203. dharta/persistence/erase.py +130 -0
  204. dharta/persistence/fork.py +241 -0
  205. dharta/persistence/gc.py +823 -0
  206. dharta/persistence/local_backend.py +220 -0
  207. dharta/persistence/manifest.py +148 -0
  208. dharta/persistence/pack.py +243 -0
  209. dharta/persistence/profile.py +216 -0
  210. dharta/persistence/reconcile.py +76 -0
  211. dharta/persistence/s3_backend.py +341 -0
  212. dharta/persistence/setup_pack.py +206 -0
  213. dharta/persistence/store.py +1348 -0
  214. dharta/persistence/stress.py +539 -0
  215. dharta/persistence/text_merge.py +70 -0
  216. dharta/persistence/workspace_paths.py +60 -0
  217. dharta/persistence/workspace_snapshot.py +584 -0
  218. dharta/policies.py +29 -0
  219. dharta/preview_admission.py +147 -0
  220. dharta/preview_model_broker.py +510 -0
  221. dharta/preview_model_readiness.py +619 -0
  222. dharta/preview_runtime_probe.py +128 -0
  223. dharta/preview_runtime_proof.py +110 -0
  224. dharta/preview_storage_reconcile.py +121 -0
  225. dharta/registry.py +137 -0
  226. dharta/release_artifacts.py +349 -0
  227. dharta/release_model_intent.py +638 -0
  228. dharta/releases.py +1090 -0
  229. dharta/response.py +175 -0
  230. dharta/runtime/__init__.py +3 -0
  231. dharta/runtime/turn_accumulator.py +231 -0
  232. dharta/secrets_bootstrap.py +88 -0
  233. dharta/server/__init__.py +22 -0
  234. dharta/server/agentcore.py +755 -0
  235. dharta/server/agentcore_agent_runtime.py +879 -0
  236. dharta/server/agentcore_client.py +979 -0
  237. dharta/server/agentcore_client_config.py +356 -0
  238. dharta/server/agentcore_client_types.py +130 -0
  239. dharta/server/agentcore_gateway_client.py +96 -0
  240. dharta/server/agentcore_internal_frames.py +769 -0
  241. dharta/server/agentcore_quota.py +120 -0
  242. dharta/server/agentcore_router.py +545 -0
  243. dharta/server/agentcore_serve.py +552 -0
  244. dharta/server/agentcore_session_socket.py +121 -0
  245. dharta/server/agentcore_sessions.py +125 -0
  246. dharta/server/agentcore_stream.py +65 -0
  247. dharta/server/agentcore_turn_recorder.py +175 -0
  248. dharta/server/agentcore_workspace.py +899 -0
  249. dharta/server/approval_store.py +506 -0
  250. dharta/server/artifact_browser_policy.py +252 -0
  251. dharta/server/artifact_execution_sessions.py +314 -0
  252. dharta/server/artifact_qualification_runtime.py +74 -0
  253. dharta/server/artifact_renderer.py +1051 -0
  254. dharta/server/artifact_runtime_binding.py +44 -0
  255. dharta/server/artifact_runtime_serve.py +190 -0
  256. dharta/server/artifact_sandbox.py +923 -0
  257. dharta/server/artifact_share_routes.py +380 -0
  258. dharta/server/artifact_stream_bridge.py +173 -0
  259. dharta/server/artifact_surface_routes.py +527 -0
  260. dharta/server/auth.py +1111 -0
  261. dharta/server/body_limit.py +89 -0
  262. dharta/server/bounded_websocket_protocol.py +108 -0
  263. dharta/server/consumer_chat_routes.py +219 -0
  264. dharta/server/consumer_routes.py +942 -0
  265. dharta/server/continuation_registry.py +328 -0
  266. dharta/server/conversation_crypto.py +202 -0
  267. dharta/server/conversation_store.py +960 -0
  268. dharta/server/conversation_transcripts.py +110 -0
  269. dharta/server/credential_guard.py +47 -0
  270. dharta/server/crypto_stores.py +214 -0
  271. dharta/server/di_factory.py +121 -0
  272. dharta/server/di_key_factory.py +57 -0
  273. dharta/server/di_resolver.py +99 -0
  274. dharta/server/embed_routes.py +358 -0
  275. dharta/server/end_user_context_binding.py +92 -0
  276. dharta/server/end_user_context_store.py +275 -0
  277. dharta/server/endpoint_pool.py +517 -0
  278. dharta/server/fastapi_app.py +704 -0
  279. dharta/server/first_party_access.py +32 -0
  280. dharta/server/git_auth.py +112 -0
  281. dharta/server/git_routes.py +183 -0
  282. dharta/server/git_transcode.py +279 -0
  283. dharta/server/identity.py +329 -0
  284. dharta/server/instance_env.py +242 -0
  285. dharta/server/instance_env_cache.py +114 -0
  286. dharta/server/instance_env_delivery.py +225 -0
  287. dharta/server/instance_routes.py +218 -0
  288. dharta/server/instance_write_lease.py +164 -0
  289. dharta/server/internal_ip.py +56 -0
  290. dharta/server/internal_routes.py +883 -0
  291. dharta/server/invocation_leases.py +268 -0
  292. dharta/server/karta_env_routes.py +194 -0
  293. dharta/server/lease_maintenance.py +97 -0
  294. dharta/server/ma_artifact_execution_routes.py +379 -0
  295. dharta/server/ma_artifact_route_context.py +29 -0
  296. dharta/server/ma_artifact_routes.py +920 -0
  297. dharta/server/ma_routes.py +680 -0
  298. dharta/server/ma_session_history_routes.py +133 -0
  299. dharta/server/ma_session_routes.py +627 -0
  300. dharta/server/ma_surface_routes.py +300 -0
  301. dharta/server/ma_task_routes.py +135 -0
  302. dharta/server/ma_workspace_downloads.py +30 -0
  303. dharta/server/ma_workspace_routes.py +235 -0
  304. dharta/server/metering.py +323 -0
  305. dharta/server/publication_attempts.py +466 -0
  306. dharta/server/publication_recovery.py +180 -0
  307. dharta/server/ratelimit.py +65 -0
  308. dharta/server/release_inventory.py +108 -0
  309. dharta/server/release_mapping.py +1094 -0
  310. dharta/server/release_publisher.py +887 -0
  311. dharta/server/release_reaper.py +182 -0
  312. dharta/server/release_tree.py +83 -0
  313. dharta/server/runtime_generation_store.py +265 -0
  314. dharta/server/runtime_rotation.py +190 -0
  315. dharta/server/schemas.py +621 -0
  316. dharta/server/serialization.py +38 -0
  317. dharta/server/serve_box_crypto.py +198 -0
  318. dharta/server/serve_host_policy.py +160 -0
  319. dharta/server/serve_surfaces.py +542 -0
  320. dharta/server/session_catalog.py +85 -0
  321. dharta/server/session_db.py +156 -0
  322. dharta/server/session_routes.py +132 -0
  323. dharta/server/session_store.py +479 -0
  324. dharta/server/sse.py +10 -0
  325. dharta/server/state.py +99 -0
  326. dharta/server/static/agent-chat/assets/agent-chat-PreviewContent.js +6 -0
  327. dharta/server/static/agent-chat/assets/agent-chat-pdf-renderer.js +54 -0
  328. dharta/server/static/agent-chat/assets/agent-chat.css +2 -0
  329. dharta/server/static/agent-chat/assets/agent-chat.js +178 -0
  330. dharta/server/static/agent-chat/assets/agent-chat.mjs +29 -0
  331. dharta/server/static/agent-chat/assets/pentagraph.worker-BaB5eTrj.js +1 -0
  332. dharta/server/static/agent-chat/fonts/dharta-arc/DhartaArc-Bold.woff2 +0 -0
  333. dharta/server/static/agent-chat/fonts/dharta-arc/DhartaArc-ExtraBold.woff2 +0 -0
  334. dharta/server/static/agent-chat/fonts/dharta-arc/DhartaArc-Medium.woff2 +0 -0
  335. dharta/server/static/agent-chat/fonts/dharta-arc/DhartaArc-Regular.woff2 +0 -0
  336. dharta/server/static/agent-chat/fonts/dharta-arc/DhartaArc-SemiBold.woff2 +0 -0
  337. dharta/server/static/agent-chat/fonts/dharta-arc/OFL.txt +88 -0
  338. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-Bold.woff2 +0 -0
  339. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-BoldItalic.woff2 +0 -0
  340. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-Medium.woff2 +0 -0
  341. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-MediumItalic.woff2 +0 -0
  342. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-Regular.woff2 +0 -0
  343. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-RegularItalic.woff2 +0 -0
  344. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-SemiBold.woff2 +0 -0
  345. dharta/server/static/agent-chat/fonts/dharta-mono/DhartaMono-SemiBoldItalic.woff2 +0 -0
  346. dharta/server/static/agent-chat/fonts/dharta-mono/OFL.txt +88 -0
  347. dharta/server/static/agent-chat/index.html +14 -0
  348. dharta/server/static/widget/v1/dharta.js +1 -0
  349. dharta/server/static/widget/v1/dharta.js.README.md +17 -0
  350. dharta/server/store_db.py +247 -0
  351. dharta/server/surface_preview_routes.py +317 -0
  352. dharta/server/surface_reaper.py +270 -0
  353. dharta/server/task_ledger.py +71 -0
  354. dharta/server/task_store.py +515 -0
  355. dharta/server/tenant_store.py +139 -0
  356. dharta/server/turn_admissions.py +327 -0
  357. dharta/server/turn_agentcore_driver.py +852 -0
  358. dharta/server/turn_continuations.py +378 -0
  359. dharta/server/turn_failure.py +78 -0
  360. dharta/server/turn_finalization.py +133 -0
  361. dharta/server/turn_identity.py +203 -0
  362. dharta/server/turn_local_driver.py +823 -0
  363. dharta/server/turn_support.py +501 -0
  364. dharta/server/turn_telemetry.py +139 -0
  365. dharta/server/turns.py +173 -0
  366. dharta/server/webhooks.py +60 -0
  367. dharta/server/workspace_access.py +164 -0
  368. dharta/server/workspace_auth.py +97 -0
  369. dharta/server/workspace_read.py +657 -0
  370. dharta/server/workspace_routes.py +152 -0
  371. dharta/session.py +166 -0
  372. dharta/subscriber_authorization_contracts.py +809 -0
  373. dharta/subscriber_sponsorship_contracts.py +781 -0
  374. dharta/subscription_credential.py +96 -0
  375. dharta/surfaces/__init__.py +57 -0
  376. dharta/surfaces/access.py +69 -0
  377. dharta/surfaces/artifact.py +62 -0
  378. dharta/surfaces/artifact_access.py +256 -0
  379. dharta/surfaces/artifact_delegation.py +205 -0
  380. dharta/surfaces/artifact_runtime.py +191 -0
  381. dharta/surfaces/browser.py +52 -0
  382. dharta/surfaces/manifest.py +99 -0
  383. dharta/surfaces/preview_bridge.py +224 -0
  384. dharta/surfaces/published_applications.py +66 -0
  385. dharta/token_signing.py +160 -0
  386. dharta/vault/__init__.py +21 -0
  387. dharta/vault/agentcore.py +33 -0
  388. dharta/vault/local.py +43 -0
  389. dharta/vault/port.py +28 -0
  390. dharta/workspace.py +487 -0
  391. dharta_runtime-0.6.77.dist-info/LICENSE +21 -0
  392. dharta_runtime-0.6.77.dist-info/METADATA +429 -0
  393. dharta_runtime-0.6.77.dist-info/RECORD +395 -0
  394. dharta_runtime-0.6.77.dist-info/WHEEL +4 -0
  395. dharta_runtime-0.6.77.dist-info/entry_points.txt +6 -0
dharta/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ from dharta.agent import Agent
2
+ from dharta.app import Dharta
3
+ from dharta.gateway import (
4
+ Gateway,
5
+ GatewayDelivery,
6
+ GatewayEvent,
7
+ HttpGateway,
8
+ LocalGateway,
9
+ ParticipantRegistry,
10
+ )
11
+ from dharta.instance import AgentInstance, InstanceManager, InstanceSession, InstanceStore
12
+ from dharta.participant import AIAgent, HumanAgent, Participant
13
+ from dharta.policies import PolicyViolationError
14
+ from dharta.registry import AgentRegistry, PublishedAgent
15
+ from dharta.response import Message, Part, Response, StreamEvent, Usage
16
+ from dharta.session import Session
17
+ from dharta.workspace import UserAgentView, WorkspaceManager
18
+
19
+ __all__ = [
20
+ "AgentInstance",
21
+ "Dharta",
22
+ "Agent",
23
+ "AIAgent",
24
+ "Gateway",
25
+ "GatewayDelivery",
26
+ "GatewayEvent",
27
+ "HttpGateway",
28
+ "HumanAgent",
29
+ "InstanceManager",
30
+ "InstanceSession",
31
+ "InstanceStore",
32
+ "LocalGateway",
33
+ "Message",
34
+ "Part",
35
+ "Participant",
36
+ "ParticipantRegistry",
37
+ "PolicyViolationError",
38
+ "AgentRegistry",
39
+ "PublishedAgent",
40
+ "Response",
41
+ "Session",
42
+ "StreamEvent",
43
+ "Usage",
44
+ "UserAgentView",
45
+ "WorkspaceManager",
46
+ ]
dharta/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from dharta.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,243 @@
1
+ """Active-release resolution for the data plane.
2
+
3
+ When a session is created for a agent URL, the data plane must learn
4
+ WHICH materialized release to run. dharta-web is authoritative: it owns
5
+ the ``Agent#current_release`` pointer that the deploy/activate
6
+ flow flips. This module fetches that pointer for an ``(org, agent)``
7
+ pair and caches it briefly so the hot path doesn't round-trip the
8
+ control plane on every session create.
9
+
10
+ Mirrors :mod:`karta.model_settings` in shape (cached control-plane GET,
11
+ ``OrgScopedTtlCache`` keyed by org first so push-invalidation matches).
12
+ The returned :class:`ActiveRelease` carries the agent's numeric id and
13
+ version, which :mod:`karta.agent_runtime` turns into a deterministic
14
+ on-disk template path via :func:`karta.releases.template_path_for`.
15
+
16
+ Nothing here is secret: a template path / commit sha / version is
17
+ operational metadata already surfaced in dashboards, so no scrubbing.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ from dataclasses import dataclass, field
24
+ from typing import Any, Dict, Optional, Tuple
25
+ from urllib.parse import quote
26
+
27
+ from dharta import observability as obs
28
+ from dharta.cache import OrgScopedTtlCache, env_number
29
+ from dharta.control_plane import ControlPlaneUnavailable, control_plane_get
30
+
31
+ logger = obs.get_logger("dharta.active_releases")
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class ActiveRelease:
36
+ """The agent's currently-active release, as resolved by dharta-web."""
37
+
38
+ agent_id: int
39
+ version: int
40
+ build_kind: str
41
+ template_path: Optional[str]
42
+ commit_sha: Optional[str]
43
+ status: Optional[str] = None
44
+ image_ref: Optional[str] = None
45
+ # RFC 0035 P3: the frozen per-(harness,version) image digest, and whether it's a
46
+ # REAL built image (vs a registry placeholder). The runtime selects the microVM
47
+ # image by this digest only when built; else it runs the constant runtime image.
48
+ harness_image_digest: Optional[str] = None
49
+ harness_image_built: bool = False
50
+ # Agent-level config the control plane attaches (RFC 0015 Phase 2b:
51
+ # ``event_visibility`` toggles). Agent-scoped, not version-pinned.
52
+ config: Dict[str, Any] = field(default_factory=dict)
53
+
54
+
55
+ # Keyed by (organization_id, agent_ref) so invalidate_org matches on
56
+ # the first tuple element. TTL is short by default: the cached value
57
+ # carries the active version, so a longer window means a freshly
58
+ # activated release keeps serving the OLD version until expiry. A new
59
+ # session is cheap to mis-route only within this window; in-flight
60
+ # sessions are pinned to their start version regardless (see
61
+ # agent_runtime). dharta-web push-invalidates on activate when wired.
62
+ _CACHE_TTL_SECONDS = env_number("DHARTA_ACTIVE_RELEASE_CACHE_TTL", 10.0, float)
63
+ _cache: OrgScopedTtlCache[ActiveRelease] = OrgScopedTtlCache(_CACHE_TTL_SECONDS)
64
+
65
+
66
+ # RFC 0035 P3: the per-(harness,version) microVM image ref, keyed by
67
+ # (org, agent_id, version) so the image resolver — which only holds ids — can read
68
+ # what fetch_active_release (slug-keyed) learned. A successful fetch records the full
69
+ # `repo@sha256:...` ref when the release froze a REAL built image, or None (placeholder
70
+ # / unbuilt) so the resolver falls back to the constant image. Bounded by active
71
+ # (agent, version) count.
72
+ _image_ref_by_id: Dict[Tuple[int, int, int], Optional[str]] = {}
73
+
74
+
75
+ def reset_active_release_cache() -> None:
76
+ """Test/ops hook: drop all cached active-release entries."""
77
+ _cache.clear()
78
+ _image_ref_by_id.clear()
79
+
80
+
81
+ def invalidate_active_release_for_org(organization_id: int) -> int:
82
+ """Drop every cached active-release entry for ``organization_id``.
83
+
84
+ Called when dharta-web posts a CacheInvalidationJob after a release
85
+ is activated or rolled back. Returns the number of entries evicted.
86
+ """
87
+ return _cache.invalidate_org(organization_id)
88
+
89
+
90
+ def ecr_repo_base() -> Optional[str]:
91
+ """The repo (no :tag / @digest) of the constant runtime image, e.g.
92
+ ``<acct>.dkr.ecr.<region>.amazonaws.com/dharta/agentcore-runtime``. A per-version
93
+ image lives in the SAME repo at a different digest, so ``repo@sha256:...`` selects
94
+ it. None when the constant image isn't configured."""
95
+ img = os.environ.get("DHARTA_AGENTCORE_RUNTIME_IMAGE")
96
+ if not img:
97
+ return None
98
+ img = img.split("@", 1)[0] # drop any digest suffix
99
+ # Drop a trailing :tag. ECR hosts carry no port, so a ':' in the LAST path
100
+ # segment is the tag separator (not a registry port).
101
+ return img.rsplit(":", 1)[0] if ":" in img.rsplit("/", 1)[-1] else img
102
+
103
+
104
+ def _record_image_ref(organization_id: int, release: ActiveRelease) -> None:
105
+ """Index this release's per-version image for the id-keyed resolver. Records the
106
+ immutable ``repo@digest`` ref only when a REAL built image was frozen (RFC 0035
107
+ P3); a placeholder / unbuilt release records None so the resolver falls back."""
108
+ key = (organization_id, release.agent_id, release.version)
109
+ if release.harness_image_built and release.harness_image_digest:
110
+ repo = ecr_repo_base()
111
+ _image_ref_by_id[key] = f"{repo}@{release.harness_image_digest}" if repo else None
112
+ else:
113
+ _image_ref_by_id[key] = None
114
+
115
+
116
+ def image_ref_for(organization_id: int, agent_id: int, version: int) -> Optional[str]:
117
+ """The immutable ``repo@digest`` microVM image to run for this release — AgentCore
118
+ pulls EXACTLY it — or None to fall back to the constant runtime image. Non-None
119
+ only when a real built per-version image was seen for this release (RFC 0035 P3:
120
+ "the right image is used, based on the agent's deployment config")."""
121
+ return _image_ref_by_id.get((organization_id, agent_id, version))
122
+
123
+
124
+ def fetch_active_release(
125
+ *,
126
+ organization_id: int,
127
+ agent_ref: str,
128
+ control_plane_url: Optional[str] = None,
129
+ service_token: Optional[str] = None,
130
+ ) -> Optional[ActiveRelease]:
131
+ """Return the active release for ``(organization_id, agent_ref)``.
132
+
133
+ ``agent_ref`` is the agent slug from the agent URL. Returns
134
+ ``None`` when the agent has no active release, is unknown, or the
135
+ control plane is unreachable. The two are distinguished by caching:
136
+ a definitive miss (404 / non-200) is negative-cached; an outage
137
+ (:class:`ControlPlaneUnavailable`) is not, so the next create retries.
138
+ """
139
+ key = (organization_id, agent_ref)
140
+ hit, cached = _cache.get(key)
141
+ if hit:
142
+ return cached
143
+
144
+ path = f"/internal/agents/{quote(agent_ref, safe='')}/active_release"
145
+ try:
146
+ payload = control_plane_get(
147
+ path,
148
+ params={"organization_id": organization_id},
149
+ control_plane_url=control_plane_url,
150
+ service_token=service_token,
151
+ )
152
+ except ControlPlaneUnavailable:
153
+ return None
154
+
155
+ if payload is None:
156
+ _cache.put(key, None)
157
+ return None
158
+
159
+ agent_id = payload.get("agent_id")
160
+ version = payload.get("version")
161
+ if not isinstance(agent_id, int) or not isinstance(version, int):
162
+ # Malformed answer — treat as a definitive miss rather than
163
+ # constructing a half-formed release we can't resolve a path for.
164
+ logger.warning(
165
+ "active_release for org=%s agent=%s missing agent_id/version",
166
+ organization_id,
167
+ agent_ref,
168
+ )
169
+ _cache.put(key, None)
170
+ return None
171
+
172
+ release = _release_from_payload(payload)
173
+ _cache.put(key, release)
174
+ _record_image_ref(organization_id, release)
175
+ return release
176
+
177
+
178
+ def fetch_release_version(
179
+ *,
180
+ organization_id: int,
181
+ agent_ref: str,
182
+ version: int,
183
+ control_plane_url: Optional[str] = None,
184
+ service_token: Optional[str] = None,
185
+ ) -> Optional[ActiveRelease]:
186
+ """Resolve a SPECIFIC activatable release (RFC 0021 P3.3 pinned scheduling).
187
+
188
+ Mirrors :func:`fetch_active_release` but hits the version-pinned resolver,
189
+ which 404s unless the release exists and is activatable. Returns ``None``
190
+ on a definitive miss (unknown org/agent/version, non-activatable) and on a
191
+ control-plane outage alike — the caller turns either into a 404/409.
192
+
193
+ Not cached: a pinned release is immutable, but pinned scheduled runs are
194
+ rare (one per cron tick), so the round-trip isn't a hot path.
195
+ # ponytail: no cache; add an immutable (org,agent,version) cache if pinned
196
+ # runs ever become hot.
197
+ """
198
+ path = (
199
+ f"/internal/agents/{quote(agent_ref, safe='')}"
200
+ f"/releases/{quote(str(version), safe='')}"
201
+ )
202
+ try:
203
+ payload = control_plane_get(
204
+ path,
205
+ params={"organization_id": organization_id},
206
+ control_plane_url=control_plane_url,
207
+ service_token=service_token,
208
+ )
209
+ except ControlPlaneUnavailable:
210
+ return None
211
+
212
+ if payload is None:
213
+ return None
214
+
215
+ if not isinstance(payload.get("agent_id"), int) or not isinstance(payload.get("version"), int):
216
+ logger.warning(
217
+ "release v%s for org=%s agent=%s missing agent_id/version",
218
+ version,
219
+ organization_id,
220
+ agent_ref,
221
+ )
222
+ return None
223
+
224
+ release = _release_from_payload(payload)
225
+ _record_image_ref(organization_id, release)
226
+ return release
227
+
228
+
229
+ def _release_from_payload(payload: Dict[str, Any]) -> ActiveRelease:
230
+ return ActiveRelease(
231
+ agent_id=int(payload["agent_id"]),
232
+ version=int(payload["version"]),
233
+ build_kind=str(payload.get("build_kind") or "file_copy"),
234
+ template_path=(str(payload["template_path"]) if payload.get("template_path") else None),
235
+ commit_sha=(str(payload["commit_sha"]) if payload.get("commit_sha") else None),
236
+ status=(str(payload["status"]) if payload.get("status") else None),
237
+ image_ref=(str(payload["image_ref"]) if payload.get("image_ref") else None),
238
+ harness_image_digest=(
239
+ str(payload["harness_image_digest"]) if payload.get("harness_image_digest") else None
240
+ ),
241
+ harness_image_built=bool(payload.get("harness_image_built")),
242
+ config=(payload["config"] if isinstance(payload.get("config"), dict) else {}),
243
+ )
dharta/agent.py ADDED
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Optional
4
+
5
+ from dharta.harness.base import AgentDefinition
6
+ from dharta.response import Response, StreamEvent
7
+
8
+ if TYPE_CHECKING:
9
+ from dharta.app import Dharta
10
+
11
+
12
+ class Agent:
13
+ def __init__(self, app: "Dharta", definition: AgentDefinition) -> None:
14
+ self._app = app
15
+ self.definition = definition
16
+
17
+ @property
18
+ def name(self) -> str:
19
+ return self.definition.name
20
+
21
+ async def send(
22
+ self,
23
+ text: str,
24
+ *,
25
+ metadata: Optional[Dict[str, Any]] = None,
26
+ thinking: bool = False,
27
+ ) -> Response:
28
+ return await self._app.send(text, metadata=metadata, agent=self, thinking=thinking)
29
+
30
+ def send_sync(
31
+ self,
32
+ text: str,
33
+ *,
34
+ metadata: Optional[Dict[str, Any]] = None,
35
+ thinking: bool = False,
36
+ ) -> Response:
37
+ return self._app.send_sync(text, metadata=metadata, agent=self, thinking=thinking)
38
+
39
+ async def stream(
40
+ self,
41
+ text: str,
42
+ *,
43
+ metadata: Optional[Dict[str, Any]] = None,
44
+ thinking: bool = False,
45
+ ) -> AsyncIterator[StreamEvent]:
46
+ async for event in self._app.stream(text, metadata=metadata, agent=self, thinking=thinking):
47
+ yield event
48
+
49
+ def stream_sync(
50
+ self,
51
+ text: str,
52
+ *,
53
+ metadata: Optional[Dict[str, Any]] = None,
54
+ thinking: bool = False,
55
+ ):
56
+ return self._app.stream_sync(text, metadata=metadata, agent=self, thinking=thinking)
57
+
58
+ def __repr__(self) -> str:
59
+ return f"Agent(name={self.name!r})"
@@ -0,0 +1,326 @@
1
+ """Canonical RFC 0070 AgentBuilder surface authority.
2
+
3
+ This value is parsed and compared in shadow only. The existing ``abs`` /
4
+ ``abid`` / ``abep`` bridge remains the sole serving authority until cutover.
5
+ Customer editing coordinates intentionally have no representation here.
6
+
7
+ ``release_status_at_issue`` is snapshot evidence, not a continuation-policy
8
+ decision. Immutable artifact/model-intent digests exclude never-built stale
9
+ reservations while a later serving milestone remains free to require active
10
+ status or permit an already-pinned built release.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import hashlib
16
+ import re
17
+ import unicodedata
18
+ from dataclasses import dataclass
19
+ from datetime import datetime, timezone
20
+ from typing import Mapping, cast
21
+
22
+ from dharta.model_contracts import ModelContractError, canonical_typed_bytes
23
+
24
+ DOMAIN = b"karta:agent-builder-surface-authority:v1\0"
25
+ AUTHORITY_TYPE = "agent_builder_surface_authority_v1"
26
+ MAX_VALIDITY_SECONDS = 3600
27
+ MAX_DATABASE_ID = (2**63) - 1
28
+ _CANONICAL_UTC = re.compile(r"\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z\Z")
29
+ _AUTHORITY_PUBLIC_ID = re.compile(r"\Aabsa_[A-Za-z0-9_-]{22,86}\Z")
30
+ _SESSION_IDENTITY = re.compile(r"\Aabss_[A-Za-z0-9_-]{22,86}\Z")
31
+ _SESSION_AUTHENTICATION_EPOCH = re.compile(r"\Aabse_[A-Za-z0-9_-]{22,86}\Z")
32
+ _CANONICAL_DATABASE_ID = re.compile(r"\A[1-9][0-9]*\Z")
33
+ _SHA256_HEX = re.compile(r"\A[0-9a-f]{64}\Z")
34
+
35
+ _ATTRIBUTE_NAMES = (
36
+ "authority_public_id",
37
+ "slot",
38
+ "assignment_id",
39
+ "assignment_revision",
40
+ "assignment_authorization_revision",
41
+ "assignment_status",
42
+ "agent_id",
43
+ "agent_organization_id",
44
+ "agent_authorization_revision",
45
+ "agent_status",
46
+ "release_id",
47
+ "release_version",
48
+ "release_agent_id",
49
+ "release_status_at_issue",
50
+ "release_kind",
51
+ "release_execution_artifact_digest",
52
+ "release_model_intent_manifest_digest",
53
+ "embed_key_id",
54
+ "embed_key_agent_id",
55
+ "embed_key_organization_id",
56
+ "embed_key_authorization_revision",
57
+ "embed_key_mode",
58
+ "embed_key_status",
59
+ "embed_key_livemode",
60
+ "model_policy_organization_id",
61
+ "billing_organization_id",
62
+ "organization_authorization_revision",
63
+ "organization_status",
64
+ "organization_first_party",
65
+ "plan_id",
66
+ "plan_key",
67
+ "plan_authorization_revision",
68
+ "session_identity",
69
+ "issued_at",
70
+ "expires_at",
71
+ "session_authentication_epoch",
72
+ "data_plane_install_id",
73
+ "data_plane_install_authorization_revision",
74
+ "install_kind",
75
+ "install_status",
76
+ "runtime_audience",
77
+ )
78
+ _FIELDS = frozenset(("schema_version", "authority_type", *_ATTRIBUTE_NAMES))
79
+ _INTEGER_FIELDS = (
80
+ "assignment_id",
81
+ "assignment_revision",
82
+ "assignment_authorization_revision",
83
+ "agent_id",
84
+ "agent_organization_id",
85
+ "agent_authorization_revision",
86
+ "release_version",
87
+ "release_agent_id",
88
+ "embed_key_id",
89
+ "embed_key_agent_id",
90
+ "embed_key_organization_id",
91
+ "embed_key_authorization_revision",
92
+ "model_policy_organization_id",
93
+ "billing_organization_id",
94
+ "organization_authorization_revision",
95
+ "plan_id",
96
+ "plan_authorization_revision",
97
+ "data_plane_install_authorization_revision",
98
+ )
99
+ _IDENTIFIER_FIELDS = (
100
+ "data_plane_install_id",
101
+ "runtime_audience",
102
+ )
103
+
104
+
105
+ def _positive_integer(value: object, field: str) -> int:
106
+ if type(value) is not int or cast(int, value) <= 0:
107
+ raise ModelContractError(f"{field} must be a positive integer")
108
+ return cast(int, value)
109
+
110
+
111
+ def _identifier(value: object, field: str) -> str:
112
+ if not isinstance(value, str):
113
+ raise ModelContractError(f"{field} must be a stable identifier")
114
+ try:
115
+ encoded = value.encode("utf-8", errors="strict")
116
+ except UnicodeEncodeError as exc:
117
+ raise ModelContractError(f"{field} must be a stable identifier") from exc
118
+ invalid = (
119
+ not encoded
120
+ or len(encoded) > 2048
121
+ or unicodedata.normalize("NFC", value) != value
122
+ or value != value.strip()
123
+ or any(character.isspace() for character in value)
124
+ or any(ord(character) <= 0x1F or 0x7F <= ord(character) <= 0x9F for character in value)
125
+ )
126
+ if invalid:
127
+ raise ModelContractError(f"{field} must be a stable identifier")
128
+ return value
129
+
130
+
131
+ def _canonical_time(value: object, field: str) -> datetime:
132
+ if not isinstance(value, str) or _CANONICAL_UTC.fullmatch(value) is None:
133
+ raise ModelContractError(f"{field} must be canonical UTC with six fractional digits")
134
+ try:
135
+ parsed = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc)
136
+ except ValueError as exc:
137
+ raise ModelContractError(
138
+ f"{field} must be canonical UTC with six fractional digits"
139
+ ) from exc
140
+ if parsed.strftime("%Y-%m-%dT%H:%M:%S.%fZ") != value:
141
+ raise ModelContractError(f"{field} must be canonical UTC with six fractional digits")
142
+ return parsed
143
+
144
+
145
+ def _validate_attributes(attributes: Mapping[str, object]) -> tuple[datetime, datetime]:
146
+ for field in _INTEGER_FIELDS:
147
+ _positive_integer(attributes[field], field)
148
+ for field in _IDENTIFIER_FIELDS:
149
+ _identifier(attributes[field], field)
150
+
151
+ opaque_ids = (
152
+ ("authority_public_id", _AUTHORITY_PUBLIC_ID),
153
+ ("session_identity", _SESSION_IDENTITY),
154
+ ("session_authentication_epoch", _SESSION_AUTHENTICATION_EPOCH),
155
+ )
156
+ for field, pattern in opaque_ids:
157
+ value = attributes[field]
158
+ if not isinstance(value, str) or pattern.fullmatch(value) is None:
159
+ raise ModelContractError(f"{field} must be a server-minted opaque id")
160
+ value = attributes["release_id"]
161
+ if (
162
+ not isinstance(value, str)
163
+ or _CANONICAL_DATABASE_ID.fullmatch(value) is None
164
+ or int(value) > MAX_DATABASE_ID
165
+ ):
166
+ raise ModelContractError("release_id must be a canonical decimal database id")
167
+ for field in (
168
+ "release_execution_artifact_digest",
169
+ "release_model_intent_manifest_digest",
170
+ ):
171
+ value = attributes[field]
172
+ if not isinstance(value, str) or _SHA256_HEX.fullmatch(value) is None:
173
+ raise ModelContractError(f"{field} must be lowercase SHA-256 hex")
174
+ for field in ("embed_key_livemode", "organization_first_party"):
175
+ if type(attributes[field]) is not bool:
176
+ raise ModelContractError(f"{field} must be a boolean")
177
+
178
+ expected_literals = {
179
+ "slot": "agent_builder",
180
+ "assignment_status": "bound",
181
+ "agent_status": "active",
182
+ "release_kind": "production",
183
+ "embed_key_mode": "live",
184
+ "embed_key_status": "active",
185
+ "organization_status": "active",
186
+ "plan_key": "internal",
187
+ "install_kind": "karta_operated",
188
+ "install_status": "active",
189
+ }
190
+ for field, expected in expected_literals.items():
191
+ if attributes[field] != expected:
192
+ raise ModelContractError(f"{field} must be {expected}")
193
+ if attributes["release_status_at_issue"] not in ("active", "superseded"):
194
+ raise ModelContractError("release must be executable")
195
+ if attributes["embed_key_livemode"] is not True:
196
+ raise ModelContractError("embed key must be live-mode")
197
+ if attributes["organization_first_party"] is not True:
198
+ raise ModelContractError("organization must be first-party")
199
+
200
+ organization_ids = {
201
+ cast(int, attributes["agent_organization_id"]),
202
+ cast(int, attributes["embed_key_organization_id"]),
203
+ cast(int, attributes["model_policy_organization_id"]),
204
+ cast(int, attributes["billing_organization_id"]),
205
+ }
206
+ if len(organization_ids) != 1:
207
+ raise ModelContractError(
208
+ "agent, embed key, model policy, and billing organization must match"
209
+ )
210
+ agent_ids = {
211
+ cast(int, attributes["agent_id"]),
212
+ cast(int, attributes["release_agent_id"]),
213
+ cast(int, attributes["embed_key_agent_id"]),
214
+ }
215
+ if len(agent_ids) != 1:
216
+ raise ModelContractError("agent, release, and embed key agent must match")
217
+
218
+ normalized_times = []
219
+ for field in ("issued_at", "expires_at"):
220
+ value = attributes[field]
221
+ if not isinstance(value, datetime) or value.tzinfo is None or value.utcoffset() is None:
222
+ raise ModelContractError(f"{field} must be a timezone-aware datetime")
223
+ normalized_times.append(value.astimezone(timezone.utc))
224
+ issued_at, expires_at = normalized_times
225
+ validity = (expires_at - issued_at).total_seconds()
226
+ if not 0 < validity <= MAX_VALIDITY_SECONDS:
227
+ raise ModelContractError(
228
+ "AgentBuilder surface authority validity must be greater than zero "
229
+ f"and at most {MAX_VALIDITY_SECONDS} seconds"
230
+ )
231
+ return issued_at, expires_at
232
+
233
+
234
+ @dataclass(frozen=True)
235
+ class AgentBuilderSurfaceAuthorityV1:
236
+ authority_public_id: str
237
+ slot: str
238
+ assignment_id: int
239
+ assignment_revision: int
240
+ assignment_authorization_revision: int
241
+ assignment_status: str
242
+ agent_id: int
243
+ agent_organization_id: int
244
+ agent_authorization_revision: int
245
+ agent_status: str
246
+ release_id: str
247
+ release_version: int
248
+ release_agent_id: int
249
+ release_status_at_issue: str
250
+ release_kind: str
251
+ release_execution_artifact_digest: str
252
+ release_model_intent_manifest_digest: str
253
+ embed_key_id: int
254
+ embed_key_agent_id: int
255
+ embed_key_organization_id: int
256
+ embed_key_authorization_revision: int
257
+ embed_key_mode: str
258
+ embed_key_status: str
259
+ embed_key_livemode: bool
260
+ model_policy_organization_id: int
261
+ billing_organization_id: int
262
+ organization_authorization_revision: int
263
+ organization_status: str
264
+ organization_first_party: bool
265
+ plan_id: int
266
+ plan_key: str
267
+ plan_authorization_revision: int
268
+ session_identity: str
269
+ issued_at: datetime
270
+ expires_at: datetime
271
+ session_authentication_epoch: str
272
+ data_plane_install_id: str
273
+ data_plane_install_authorization_revision: int
274
+ install_kind: str
275
+ install_status: str
276
+ runtime_audience: str
277
+
278
+ def __post_init__(self) -> None:
279
+ # The public dataclass constructor is as strict as ``from_mapping``;
280
+ # callers cannot create or digest an invalid authority by bypassing the
281
+ # wire parser.
282
+ issued_at, expires_at = _validate_attributes(
283
+ {name: getattr(self, name) for name in _ATTRIBUTE_NAMES}
284
+ )
285
+ object.__setattr__(self, "issued_at", issued_at)
286
+ object.__setattr__(self, "expires_at", expires_at)
287
+
288
+ @classmethod
289
+ def from_mapping(cls, value: object) -> "AgentBuilderSurfaceAuthorityV1":
290
+ if not isinstance(value, Mapping) or not all(isinstance(key, str) for key in value):
291
+ raise ModelContractError(
292
+ "AgentBuilderSurfaceAuthorityV1 payload must be an object with string keys"
293
+ )
294
+ if frozenset(value) != _FIELDS:
295
+ raise ModelContractError(
296
+ "AgentBuilderSurfaceAuthorityV1 fields do not match the V1 contract"
297
+ )
298
+ if type(value.get("schema_version")) is not int or value.get("schema_version") != 1:
299
+ raise ModelContractError("AgentBuilderSurfaceAuthorityV1 schema_version must be 1")
300
+ if value.get("authority_type") != AUTHORITY_TYPE:
301
+ raise ModelContractError(f"authority_type must be {AUTHORITY_TYPE}")
302
+
303
+ attributes = {name: value[name] for name in _ATTRIBUTE_NAMES}
304
+ issued_at = _canonical_time(attributes["issued_at"], "issued_at")
305
+ expires_at = _canonical_time(attributes["expires_at"], "expires_at")
306
+ attributes["issued_at"] = issued_at
307
+ attributes["expires_at"] = expires_at
308
+
309
+ return cls(**attributes)
310
+
311
+ def as_dict(self) -> dict[str, object]:
312
+ values: dict[str, object] = {name: getattr(self, name) for name in _ATTRIBUTE_NAMES}
313
+ values["issued_at"] = self.issued_at.astimezone(timezone.utc).strftime(
314
+ "%Y-%m-%dT%H:%M:%S.%fZ"
315
+ )
316
+ values["expires_at"] = self.expires_at.astimezone(timezone.utc).strftime(
317
+ "%Y-%m-%dT%H:%M:%S.%fZ"
318
+ )
319
+ return {
320
+ "schema_version": 1,
321
+ "authority_type": AUTHORITY_TYPE,
322
+ **values,
323
+ }
324
+
325
+ def contract_digest(self) -> str:
326
+ return hashlib.sha256(DOMAIN + canonical_typed_bytes(self.as_dict())).hexdigest()