pyfect-dev 0.1.0__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 (1265) hide show
  1. pyfect/__init__.py +729 -0
  2. pyfect/_all.py +242 -0
  3. pyfect/_background.py +28 -0
  4. pyfect/_binary_codecs.py +124 -0
  5. pyfect/_cached.py +165 -0
  6. pyfect/_catch.py +128 -0
  7. pyfect/_catch_reason.py +574 -0
  8. pyfect/_concurrency.py +291 -0
  9. pyfect/_context_effects.py +163 -0
  10. pyfect/_context_managers.py +76 -0
  11. pyfect/_core.py +368 -0
  12. pyfect/_digits.py +71 -0
  13. pyfect/_effect_args.py +46 -0
  14. pyfect/_effect_base.py +71 -0
  15. pyfect/_effect_concurrency.py +133 -0
  16. pyfect/_effect_eager.py +103 -0
  17. pyfect/_effect_errors.py +344 -0
  18. pyfect/_effect_folding.py +110 -0
  19. pyfect/_effect_hash.py +140 -0
  20. pyfect/_effect_logging.py +57 -0
  21. pyfect/_effect_metrics.py +102 -0
  22. pyfect/_effect_resources.py +179 -0
  23. pyfect/_effect_services.py +25 -0
  24. pyfect/_effect_timing.py +199 -0
  25. pyfect/_effect_tracing.py +99 -0
  26. pyfect/_equal.py +195 -0
  27. pyfect/_extras.py +43 -0
  28. pyfect/_fiber.py +969 -0
  29. pyfect/_fiber_all.py +134 -0
  30. pyfect/_fiber_collections.py +106 -0
  31. pyfect/_fn.py +706 -0
  32. pyfect/_hamt.py +174 -0
  33. pyfect/_interrupt_reason.py +33 -0
  34. pyfect/_isaac.py +149 -0
  35. pyfect/_iterables.py +231 -0
  36. pyfect/_js.py +263 -0
  37. pyfect/_js_date.py +87 -0
  38. pyfect/_json_text.py +286 -0
  39. pyfect/_json_value.py +9 -0
  40. pyfect/_layer_core.py +403 -0
  41. pyfect/_layer_for_life.py +33 -0
  42. pyfect/_layer_tracing.py +70 -0
  43. pyfect/_locked_ref.py +147 -0
  44. pyfect/_loop_thread.py +152 -0
  45. pyfect/_metric_ref.py +29 -0
  46. pyfect/_one_or_many.py +14 -0
  47. pyfect/_os_wait.py +118 -0
  48. pyfect/_path_posix.py +129 -0
  49. pyfect/_primitives.py +434 -0
  50. pyfect/_public.py +36 -0
  51. pyfect/_reasons.py +64 -0
  52. pyfect/_released.py +67 -0
  53. pyfect/_root.py +87 -0
  54. pyfect/_round_robin.py +73 -0
  55. pyfect/_some.py +17 -0
  56. pyfect/_stack.py +52 -0
  57. pyfect/_stack_frame.py +114 -0
  58. pyfect/_string_hash.py +35 -0
  59. pyfect/_subscriber_queue.py +47 -0
  60. pyfect/_tags.py +14 -0
  61. pyfect/_tracer_ref.py +21 -0
  62. pyfect/_tx_ops.py +77 -0
  63. pyfect/_unsubscripted.py +23 -0
  64. pyfect/_url.py +54 -0
  65. pyfect/_waiters.py +127 -0
  66. pyfect/_wake_tracking.py +98 -0
  67. pyfect/_wire_codec.py +123 -0
  68. pyfect/ai/__init__.py +73 -0
  69. pyfect/ai/_approvals.py +249 -0
  70. pyfect/ai/_decision_answers.py +185 -0
  71. pyfect/ai/_generated_client.py +298 -0
  72. pyfect/ai/_generated_support.py +84 -0
  73. pyfect/ai/_mcp/__init__.py +1 -0
  74. pyfect/ai/_mcp/batch.py +68 -0
  75. pyfect/ai/_mcp/client_transport.py +412 -0
  76. pyfect/ai/_mcp/client_wire.py +284 -0
  77. pyfect/ai/_mcp/core.py +490 -0
  78. pyfect/ai/_mcp/dispatch.py +1048 -0
  79. pyfect/ai/_mcp/http.py +462 -0
  80. pyfect/ai/_mcp/http_admission.py +269 -0
  81. pyfect/ai/_mcp/http_status.py +27 -0
  82. pyfect/ai/_mcp/input_wire.py +226 -0
  83. pyfect/ai/_mcp/log_levels.py +55 -0
  84. pyfect/ai/_mcp/param_headers.py +63 -0
  85. pyfect/ai/_mcp/projection.py +248 -0
  86. pyfect/ai/_mcp/register.py +683 -0
  87. pyfect/ai/_mcp/reverse_policy.py +155 -0
  88. pyfect/ai/_mcp/routing_header.py +24 -0
  89. pyfect/ai/_mcp/sessions.py +114 -0
  90. pyfect/ai/_mcp/stdio.py +110 -0
  91. pyfect/ai/_mcp/subscriptions.py +134 -0
  92. pyfect/ai/_mcp/tool_schema.py +35 -0
  93. pyfect/ai/_noul_answers.py +64 -0
  94. pyfect/ai/_openai_all_of.py +137 -0
  95. pyfect/ai/_openai_errors.py +233 -0
  96. pyfect/ai/_provider.py +439 -0
  97. pyfect/ai/_provider_tools.py +129 -0
  98. pyfect/ai/_stream_resolution.py +231 -0
  99. pyfect/ai/_structured_output_checks.py +138 -0
  100. pyfect/ai/_structured_output_codec.py +229 -0
  101. pyfect/ai/_structured_output_json.py +109 -0
  102. pyfect/ai/_tool_call_ids.py +80 -0
  103. pyfect/ai/ai_error.py +785 -0
  104. pyfect/ai/anthropic/__init__.py +28 -0
  105. pyfect/ai/anthropic/_errors.py +164 -0
  106. pyfect/ai/anthropic/_prompt.py +375 -0
  107. pyfect/ai/anthropic/_response.py +443 -0
  108. pyfect/ai/anthropic/_schema.py +206 -0
  109. pyfect/ai/anthropic/_stream.py +377 -0
  110. pyfect/ai/anthropic/_tools.py +248 -0
  111. pyfect/ai/anthropic/client.py +289 -0
  112. pyfect/ai/anthropic/config.py +32 -0
  113. pyfect/ai/anthropic/error.py +27 -0
  114. pyfect/ai/anthropic/language_model.py +366 -0
  115. pyfect/ai/anthropic/telemetry.py +51 -0
  116. pyfect/ai/anthropic/tool.py +570 -0
  117. pyfect/ai/anthropic_structured_output.py +138 -0
  118. pyfect/ai/chat.py +548 -0
  119. pyfect/ai/cloudflare/__init__.py +15 -0
  120. pyfect/ai/cloudflare/_errors.py +108 -0
  121. pyfect/ai/cloudflare/client.py +174 -0
  122. pyfect/ai/cloudflare/decision_model.py +117 -0
  123. pyfect/ai/cloudflare/schema.py +144 -0
  124. pyfect/ai/decision.py +290 -0
  125. pyfect/ai/decision_model.py +283 -0
  126. pyfect/ai/embedding_model.py +177 -0
  127. pyfect/ai/id_generator.py +79 -0
  128. pyfect/ai/language_model.py +1077 -0
  129. pyfect/ai/mcp_client.py +682 -0
  130. pyfect/ai/mcp_client_error.py +223 -0
  131. pyfect/ai/mcp_protocol.py +205 -0
  132. pyfect/ai/mcp_schema.py +1300 -0
  133. pyfect/ai/mcp_server.py +404 -0
  134. pyfect/ai/model.py +56 -0
  135. pyfect/ai/openai/__init__.py +49 -0
  136. pyfect/ai/openai/_errors.py +89 -0
  137. pyfect/ai/openai/_prompt.py +527 -0
  138. pyfect/ai/openai/_requests.py +34 -0
  139. pyfect/ai/openai/_response.py +569 -0
  140. pyfect/ai/openai/_schema.py +769 -0
  141. pyfect/ai/openai/_stream.py +771 -0
  142. pyfect/ai/openai/_tools.py +128 -0
  143. pyfect/ai/openai/_web_socket.py +295 -0
  144. pyfect/ai/openai/client.py +296 -0
  145. pyfect/ai/openai/client_generated.py +123 -0
  146. pyfect/ai/openai/config.py +34 -0
  147. pyfect/ai/openai/decision_model.py +177 -0
  148. pyfect/ai/openai/embedding_model.py +116 -0
  149. pyfect/ai/openai/error.py +8 -0
  150. pyfect/ai/openai/generated/__init__.py +7213 -0
  151. pyfect/ai/openai/generated/_recursive.py +18 -0
  152. pyfect/ai/openai/generated/_schemas_0.py +1015 -0
  153. pyfect/ai/openai/generated/_schemas_1.py +1016 -0
  154. pyfect/ai/openai/generated/_schemas_2.py +1017 -0
  155. pyfect/ai/openai/generated/_schemas_3.py +615 -0
  156. pyfect/ai/openai/generated/client.py +5298 -0
  157. pyfect/ai/openai/generated/types.py +8123 -0
  158. pyfect/ai/openai/language_model.py +304 -0
  159. pyfect/ai/openai/telemetry.py +19 -0
  160. pyfect/ai/openai/tool.py +391 -0
  161. pyfect/ai/openai_compat/__init__.py +25 -0
  162. pyfect/ai/openai_compat/_prompt.py +191 -0
  163. pyfect/ai/openai_compat/_request.py +153 -0
  164. pyfect/ai/openai_compat/_response.py +407 -0
  165. pyfect/ai/openai_compat/_schema.py +97 -0
  166. pyfect/ai/openai_compat/client.py +234 -0
  167. pyfect/ai/openai_compat/config.py +32 -0
  168. pyfect/ai/openai_compat/embedding_model.py +139 -0
  169. pyfect/ai/openai_compat/error.py +7 -0
  170. pyfect/ai/openai_compat/language_model.py +245 -0
  171. pyfect/ai/openai_compat/telemetry.py +51 -0
  172. pyfect/ai/openai_structured_output.py +118 -0
  173. pyfect/ai/openrouter/__init__.py +36 -0
  174. pyfect/ai/openrouter/_errors.py +186 -0
  175. pyfect/ai/openrouter/_prompt.py +272 -0
  176. pyfect/ai/openrouter/_response.py +226 -0
  177. pyfect/ai/openrouter/_stream.py +320 -0
  178. pyfect/ai/openrouter/client.py +283 -0
  179. pyfect/ai/openrouter/config.py +36 -0
  180. pyfect/ai/openrouter/decision_model.py +161 -0
  181. pyfect/ai/openrouter/error.py +23 -0
  182. pyfect/ai/openrouter/generated/__init__.py +3029 -0
  183. pyfect/ai/openrouter/generated/_recursive.py +15 -0
  184. pyfect/ai/openrouter/generated/_schemas_0.py +1015 -0
  185. pyfect/ai/openrouter/generated/_schemas_1.py +522 -0
  186. pyfect/ai/openrouter/generated/client.py +1445 -0
  187. pyfect/ai/openrouter/generated/types.py +4769 -0
  188. pyfect/ai/openrouter/language_model.py +345 -0
  189. pyfect/ai/openrouter/schema.py +165 -0
  190. pyfect/ai/prompt.py +664 -0
  191. pyfect/ai/response.py +768 -0
  192. pyfect/ai/response_id_tracker.py +82 -0
  193. pyfect/ai/telemetry.py +126 -0
  194. pyfect/ai/tokenizer.py +61 -0
  195. pyfect/ai/tool.py +536 -0
  196. pyfect/ai/toolkit.py +490 -0
  197. pyfect/ai/typesafe/__init__.py +17 -0
  198. pyfect/ai/typesafe/_errors.py +120 -0
  199. pyfect/ai/typesafe/client.py +146 -0
  200. pyfect/ai/typesafe/config.py +34 -0
  201. pyfect/ai/typesafe/decision_model.py +90 -0
  202. pyfect/ai/typesafe/schema.py +140 -0
  203. pyfect/batching/__init__.py +58 -0
  204. pyfect/batching/_api.py +71 -0
  205. pyfect/batching/_engine.py +229 -0
  206. pyfect/batching/_from_effect.py +76 -0
  207. pyfect/batching/_persisted.py +98 -0
  208. pyfect/batching/_request.py +133 -0
  209. pyfect/batching/_resolver.py +477 -0
  210. pyfect/batching/_with_cache.py +90 -0
  211. pyfect/big_decimal.py +500 -0
  212. pyfect/brand.py +114 -0
  213. pyfect/byte_size.py +354 -0
  214. pyfect/cache/__init__.py +29 -0
  215. pyfect/cache/_cache.py +426 -0
  216. pyfect/cache/_expiry.py +69 -0
  217. pyfect/cache/_scoped_cache.py +546 -0
  218. pyfect/case.py +174 -0
  219. pyfect/cause.py +462 -0
  220. pyfect/channel/__init__.py +155 -0
  221. pyfect/channel/_base.py +92 -0
  222. pyfect/channel/_catch.py +158 -0
  223. pyfect/channel/_catch_reason.py +572 -0
  224. pyfect/channel/_channel.py +158 -0
  225. pyfect/channel/_combinators.py +220 -0
  226. pyfect/channel/_concurrency_methods.py +217 -0
  227. pyfect/channel/_concurrent_map.py +118 -0
  228. pyfect/channel/_constructors.py +349 -0
  229. pyfect/channel/_context.py +232 -0
  230. pyfect/channel/_error_methods.py +336 -0
  231. pyfect/channel/_errors.py +180 -0
  232. pyfect/channel/_filters.py +225 -0
  233. pyfect/channel/_lifecycle.py +71 -0
  234. pyfect/channel/_lifecycle_methods.py +206 -0
  235. pyfect/channel/_loop.py +100 -0
  236. pyfect/channel/_merge.py +246 -0
  237. pyfect/channel/_repeat.py +154 -0
  238. pyfect/channel/_run.py +149 -0
  239. pyfect/channel/_run_methods.py +341 -0
  240. pyfect/channel/_sinks.py +88 -0
  241. pyfect/channel/_sources.py +238 -0
  242. pyfect/channel/_text.py +176 -0
  243. pyfect/channel/_transform_methods.py +415 -0
  244. pyfect/channel/_upstream.py +67 -0
  245. pyfect/channel_schema.py +131 -0
  246. pyfect/cli/__init__.py +79 -0
  247. pyfect/cli/_ansi.py +82 -0
  248. pyfect/cli/_command.py +469 -0
  249. pyfect/cli/_config.py +164 -0
  250. pyfect/cli/_environment.py +10 -0
  251. pyfect/cli/_help.py +195 -0
  252. pyfect/cli/_lexer.py +81 -0
  253. pyfect/cli/_parser.py +465 -0
  254. pyfect/cli/_settings.py +85 -0
  255. pyfect/cli/_suggest.py +33 -0
  256. pyfect/cli/_width.py +134 -0
  257. pyfect/cli/_wizard.py +317 -0
  258. pyfect/cli/argument.py +212 -0
  259. pyfect/cli/cli_config.py +40 -0
  260. pyfect/cli/cli_error.py +242 -0
  261. pyfect/cli/cli_output.py +305 -0
  262. pyfect/cli/command.py +440 -0
  263. pyfect/cli/completions/__init__.py +50 -0
  264. pyfect/cli/completions/_completer.ps1 +190 -0
  265. pyfect/cli/completions/_descriptor.py +182 -0
  266. pyfect/cli/completions/bash.py +300 -0
  267. pyfect/cli/completions/fish.py +164 -0
  268. pyfect/cli/completions/powershell.py +156 -0
  269. pyfect/cli/completions/zsh.py +189 -0
  270. pyfect/cli/flag.py +246 -0
  271. pyfect/cli/global_flag.py +99 -0
  272. pyfect/cli/help_doc.py +63 -0
  273. pyfect/cli/param.py +789 -0
  274. pyfect/cli/primitive.py +308 -0
  275. pyfect/cli/prompt/__init__.py +75 -0
  276. pyfect/cli/prompt/_auto_complete.py +205 -0
  277. pyfect/cli/prompt/_choices.py +104 -0
  278. pyfect/cli/prompt/_confirm.py +195 -0
  279. pyfect/cli/prompt/_core.py +512 -0
  280. pyfect/cli/prompt/_date.py +173 -0
  281. pyfect/cli/prompt/_date_parts.py +387 -0
  282. pyfect/cli/prompt/_file.py +372 -0
  283. pyfect/cli/prompt/_multi_select.py +204 -0
  284. pyfect/cli/prompt/_number.py +257 -0
  285. pyfect/cli/prompt/_select.py +117 -0
  286. pyfect/cli/prompt/_text.py +239 -0
  287. pyfect/cli/terminal_capabilities.py +118 -0
  288. pyfect/clock.py +150 -0
  289. pyfect/cluster/__init__.py +155 -0
  290. pyfect/cluster/_cluster_abandon.py +36 -0
  291. pyfect/cluster/_cluster_layer.py +122 -0
  292. pyfect/cluster/_entity_activation.py +16 -0
  293. pyfect/cluster/_entity_manager/__init__.py +22 -0
  294. pyfect/cluster/_entity_manager/_activation.py +540 -0
  295. pyfect/cluster/_entity_manager/_core.py +186 -0
  296. pyfect/cluster/_entity_manager/_decode.py +60 -0
  297. pyfect/cluster/_entity_manager/_manager.py +423 -0
  298. pyfect/cluster/_entity_manager/_state.py +113 -0
  299. pyfect/cluster/_entity_reaper.py +94 -0
  300. pyfect/cluster/_hash.py +13 -0
  301. pyfect/cluster/_interruptors.py +88 -0
  302. pyfect/cluster/_resource_map.py +179 -0
  303. pyfect/cluster/_resource_ref.py +266 -0
  304. pyfect/cluster/_shard_lock.py +14 -0
  305. pyfect/cluster/cluster_cron.py +230 -0
  306. pyfect/cluster/cluster_error.py +81 -0
  307. pyfect/cluster/cluster_http.py +210 -0
  308. pyfect/cluster/cluster_metrics.py +54 -0
  309. pyfect/cluster/cluster_schema.py +137 -0
  310. pyfect/cluster/cluster_socket.py +197 -0
  311. pyfect/cluster/cluster_workflow_engine/__init__.py +24 -0
  312. pyfect/cluster/cluster_workflow_engine/_engine.py +1099 -0
  313. pyfect/cluster/cluster_workflow_engine/_entities.py +298 -0
  314. pyfect/cluster/deliver_at.py +31 -0
  315. pyfect/cluster/entity/__init__.py +39 -0
  316. pyfect/cluster/entity/_entity.py +332 -0
  317. pyfect/cluster/entity/_handlers.py +168 -0
  318. pyfect/cluster/entity/_keep_alive.py +74 -0
  319. pyfect/cluster/entity/_queue.py +103 -0
  320. pyfect/cluster/entity/_request.py +34 -0
  321. pyfect/cluster/entity/_services.py +23 -0
  322. pyfect/cluster/entity/_test_client.py +237 -0
  323. pyfect/cluster/entity_address.py +25 -0
  324. pyfect/cluster/entity_id.py +20 -0
  325. pyfect/cluster/entity_proxy.py +161 -0
  326. pyfect/cluster/entity_proxy_server.py +103 -0
  327. pyfect/cluster/entity_resource.py +122 -0
  328. pyfect/cluster/entity_type.py +20 -0
  329. pyfect/cluster/envelope.py +307 -0
  330. pyfect/cluster/http_runner.py +254 -0
  331. pyfect/cluster/k8s_http_client.py +281 -0
  332. pyfect/cluster/k8s_types.py +1394 -0
  333. pyfect/cluster/machine_id.py +21 -0
  334. pyfect/cluster/message.py +219 -0
  335. pyfect/cluster/message_storage/__init__.py +67 -0
  336. pyfect/cluster/message_storage/_encoded.py +393 -0
  337. pyfect/cluster/message_storage/_memory.py +386 -0
  338. pyfect/cluster/message_storage/_noop.py +109 -0
  339. pyfect/cluster/message_storage/_service.py +388 -0
  340. pyfect/cluster/reply.py +236 -0
  341. pyfect/cluster/runner.py +32 -0
  342. pyfect/cluster/runner_address.py +23 -0
  343. pyfect/cluster/runner_health.py +93 -0
  344. pyfect/cluster/runner_server.py +286 -0
  345. pyfect/cluster/runner_storage.py +212 -0
  346. pyfect/cluster/runners/__init__.py +55 -0
  347. pyfect/cluster/runners/_local.py +460 -0
  348. pyfect/cluster/runners/_noop.py +57 -0
  349. pyfect/cluster/runners/_rpc.py +290 -0
  350. pyfect/cluster/runners/_service.py +113 -0
  351. pyfect/cluster/shard_id.py +39 -0
  352. pyfect/cluster/sharding/__init__.py +12 -0
  353. pyfect/cluster/sharding/_acquisition.py +490 -0
  354. pyfect/cluster/sharding/_clients.py +271 -0
  355. pyfect/cluster/sharding/_make.py +388 -0
  356. pyfect/cluster/sharding/_routing.py +296 -0
  357. pyfect/cluster/sharding/_runners_sync.py +198 -0
  358. pyfect/cluster/sharding/_service.py +91 -0
  359. pyfect/cluster/sharding/_singletons.py +183 -0
  360. pyfect/cluster/sharding/_state.py +296 -0
  361. pyfect/cluster/sharding/_storage_loop.py +421 -0
  362. pyfect/cluster/sharding_config.py +230 -0
  363. pyfect/cluster/sharding_registration_event.py +28 -0
  364. pyfect/cluster/single_runner.py +49 -0
  365. pyfect/cluster/singleton.py +36 -0
  366. pyfect/cluster/singleton_address.py +20 -0
  367. pyfect/cluster/snowflake.py +133 -0
  368. pyfect/cluster/socket_runner.py +67 -0
  369. pyfect/cluster/sql_message_storage.py +1001 -0
  370. pyfect/cluster/sql_runner_storage.py +841 -0
  371. pyfect/cluster/test_runner.py +23 -0
  372. pyfect/config/__init__.py +93 -0
  373. pyfect/config/_all.py +96 -0
  374. pyfect/config/_collections.py +291 -0
  375. pyfect/config/_config.py +261 -0
  376. pyfect/config/_constructors.py +106 -0
  377. pyfect/config/_error.py +27 -0
  378. pyfect/config/_leaf.py +92 -0
  379. pyfect/config/_scalars.py +193 -0
  380. pyfect/config/_schema.py +340 -0
  381. pyfect/config_provider/__init__.py +60 -0
  382. pyfect/config_provider/_dir.py +84 -0
  383. pyfect/config_provider/_dotenv.py +127 -0
  384. pyfect/config_provider/_env.py +79 -0
  385. pyfect/config_provider/_layers.py +80 -0
  386. pyfect/config_provider/_node.py +90 -0
  387. pyfect/config_provider/_provider.py +118 -0
  388. pyfect/config_provider/_unknown.py +62 -0
  389. pyfect/console/__init__.py +63 -0
  390. pyfect/console/_effects.py +134 -0
  391. pyfect/console/_live.py +156 -0
  392. pyfect/console/_service.py +49 -0
  393. pyfect/console/_table.py +90 -0
  394. pyfect/context.py +414 -0
  395. pyfect/cron/__init__.py +30 -0
  396. pyfect/cron/_model.py +183 -0
  397. pyfect/cron/_search.py +268 -0
  398. pyfect/cron/_text.py +202 -0
  399. pyfect/cron/_wall.py +42 -0
  400. pyfect/crypto.py +257 -0
  401. pyfect/date_time/__init__.py +77 -0
  402. pyfect/date_time/_calendar.py +209 -0
  403. pyfect/date_time/_current.py +118 -0
  404. pyfect/date_time/_epoch.py +22 -0
  405. pyfect/date_time/_iso.py +80 -0
  406. pyfect/date_time/_zones.py +135 -0
  407. pyfect/date_time/intl.py +144 -0
  408. pyfect/deferred.py +145 -0
  409. pyfect/devtools/__init__.py +24 -0
  410. pyfect/devtools/client.py +323 -0
  411. pyfect/devtools/layers.py +32 -0
  412. pyfect/devtools/schema.py +301 -0
  413. pyfect/devtools/server.py +72 -0
  414. pyfect/duration.py +295 -0
  415. pyfect/effect.py +565 -0
  416. pyfect/effectable.py +37 -0
  417. pyfect/encoding/__init__.py +62 -0
  418. pyfect/encoding/_archive.py +197 -0
  419. pyfect/encoding/_json_array_scanner.py +477 -0
  420. pyfect/encoding/base64.py +23 -0
  421. pyfect/encoding/base64_url.py +19 -0
  422. pyfect/encoding/encoding_error.py +17 -0
  423. pyfect/encoding/hex.py +28 -0
  424. pyfect/encoding/ini.py +188 -0
  425. pyfect/encoding/json_array.py +246 -0
  426. pyfect/encoding/ndjson.py +461 -0
  427. pyfect/encoding/schema_binary/__init__.py +257 -0
  428. pyfect/encoding/schema_binary/_channels.py +173 -0
  429. pyfect/encoding/schema_binary/_compile.py +584 -0
  430. pyfect/encoding/schema_binary/_decode.py +848 -0
  431. pyfect/encoding/schema_binary/_dictionary.py +90 -0
  432. pyfect/encoding/schema_binary/_encode.py +838 -0
  433. pyfect/encoding/schema_binary/_fingerprint.py +168 -0
  434. pyfect/encoding/schema_binary/_layout.py +350 -0
  435. pyfect/encoding/schema_binary/_literals.py +47 -0
  436. pyfect/encoding/schema_binary/_parser.py +163 -0
  437. pyfect/encoding/schema_binary/_reader.py +148 -0
  438. pyfect/encoding/schema_binary/_target.py +310 -0
  439. pyfect/encoding/schema_binary/_values.py +133 -0
  440. pyfect/encoding/schema_binary/_wire.py +253 -0
  441. pyfect/encoding/sse.py +476 -0
  442. pyfect/encoding/tar/__init__.py +396 -0
  443. pyfect/encoding/tar/_decoder.py +220 -0
  444. pyfect/encoding/tar/_encoder.py +83 -0
  445. pyfect/encoding/tar/_header.py +494 -0
  446. pyfect/encoding/tar/_model.py +82 -0
  447. pyfect/encoding/toml.py +375 -0
  448. pyfect/encoding/xml/__init__.py +222 -0
  449. pyfect/encoding/xml/_chars.py +119 -0
  450. pyfect/encoding/xml/_collector.py +106 -0
  451. pyfect/encoding/xml/_inputs.py +126 -0
  452. pyfect/encoding/xml/_model.py +114 -0
  453. pyfect/encoding/xml/_parser.py +694 -0
  454. pyfect/encoding/xml/_scanner.py +180 -0
  455. pyfect/encoding/xml/_writer.py +238 -0
  456. pyfect/encoding/yaml.py +739 -0
  457. pyfect/encoding/zip/__init__.py +392 -0
  458. pyfect/encoding/zip/_decoder.py +378 -0
  459. pyfect/encoding/zip/_format.py +122 -0
  460. pyfect/encoding/zip/_inflate.py +65 -0
  461. pyfect/encoding/zip/_model.py +86 -0
  462. pyfect/encoding/zip/_writer.py +311 -0
  463. pyfect/error_reporter.py +240 -0
  464. pyfect/errors.py +321 -0
  465. pyfect/eventlog/__init__.py +77 -0
  466. pyfect/eventlog/_conflicts.py +94 -0
  467. pyfect/eventlog/_crypto.py +64 -0
  468. pyfect/eventlog/_identity.py +26 -0
  469. pyfect/eventlog/_identity_derivation.py +79 -0
  470. pyfect/eventlog/_transferable_bytes.py +55 -0
  471. pyfect/eventlog/_uuid.py +33 -0
  472. pyfect/eventlog/event.py +115 -0
  473. pyfect/eventlog/event_group.py +55 -0
  474. pyfect/eventlog/event_journal.py +630 -0
  475. pyfect/eventlog/event_log.py +1039 -0
  476. pyfect/eventlog/event_log_encryption.py +219 -0
  477. pyfect/eventlog/event_log_message.py +357 -0
  478. pyfect/eventlog/event_log_remote.py +465 -0
  479. pyfect/eventlog/event_log_server.py +442 -0
  480. pyfect/eventlog/event_log_server_encrypted.py +322 -0
  481. pyfect/eventlog/event_log_server_unencrypted.py +814 -0
  482. pyfect/eventlog/event_log_session_auth.py +250 -0
  483. pyfect/eventlog/event_row.py +423 -0
  484. pyfect/eventlog/sql_event_journal.py +692 -0
  485. pyfect/eventlog/sql_event_log_server_encrypted.py +440 -0
  486. pyfect/eventlog/sql_event_log_server_unencrypted.py +568 -0
  487. pyfect/execution_plan/__init__.py +42 -0
  488. pyfect/execution_plan/_events.py +128 -0
  489. pyfect/execution_plan/_model.py +108 -0
  490. pyfect/execution_plan/_run.py +176 -0
  491. pyfect/exit.py +205 -0
  492. pyfect/fiber_handle.py +305 -0
  493. pyfect/fiber_map.py +350 -0
  494. pyfect/fiber_set.py +232 -0
  495. pyfect/file_system/__init__.py +69 -0
  496. pyfect/file_system/_copy.py +116 -0
  497. pyfect/file_system/_errors.py +32 -0
  498. pyfect/file_system/_file.py +177 -0
  499. pyfect/file_system/_live.py +351 -0
  500. pyfect/file_system/_model.py +72 -0
  501. pyfect/file_system/_noop.py +189 -0
  502. pyfect/file_system/_service.py +336 -0
  503. pyfect/file_system/_stat.py +69 -0
  504. pyfect/file_system/_watch.py +107 -0
  505. pyfect/filters.py +245 -0
  506. pyfect/graph/__init__.py +101 -0
  507. pyfect/graph/_all_pairs.py +150 -0
  508. pyfect/graph/_combine.py +259 -0
  509. pyfect/graph/_compact.py +143 -0
  510. pyfect/graph/_components.py +200 -0
  511. pyfect/graph/_cycles.py +144 -0
  512. pyfect/graph/_enumerate.py +168 -0
  513. pyfect/graph/_errors.py +51 -0
  514. pyfect/graph/_flow.py +164 -0
  515. pyfect/graph/_forest.py +109 -0
  516. pyfect/graph/_graph.py +269 -0
  517. pyfect/graph/_lowlink.py +98 -0
  518. pyfect/graph/_matching.py +101 -0
  519. pyfect/graph/_mutate.py +211 -0
  520. pyfect/graph/_query.py +138 -0
  521. pyfect/graph/_records.py +119 -0
  522. pyfect/graph/_render.py +109 -0
  523. pyfect/graph/_shortest.py +274 -0
  524. pyfect/graph/_snapshot.py +50 -0
  525. pyfect/graph/_store.py +136 -0
  526. pyfect/graph/_traverse.py +289 -0
  527. pyfect/graph/_view.py +384 -0
  528. pyfect/graph/_walker.py +70 -0
  529. pyfect/graphql/__init__.py +87 -0
  530. pyfect/graphql/_codec.py +117 -0
  531. pyfect/graphql/_http.py +309 -0
  532. pyfect/graphql/_schemas.py +39 -0
  533. pyfect/graphql/_slices.py +110 -0
  534. pyfect/graphql/_template.py +111 -0
  535. pyfect/graphql/_types.py +115 -0
  536. pyfect/graphql/_ws.py +395 -0
  537. pyfect/graphql/_ws_messages.py +120 -0
  538. pyfect/graphql/client.py +428 -0
  539. pyfect/graphql/client_error.py +285 -0
  540. pyfect/graphql/group.py +142 -0
  541. pyfect/graphql/middleware.py +98 -0
  542. pyfect/graphql/operation.py +409 -0
  543. pyfect/graphql/protocol.py +119 -0
  544. pyfect/graphql/resolver.py +574 -0
  545. pyfect/graphql/template.py +61 -0
  546. pyfect/hash_map.py +317 -0
  547. pyfect/hash_ring.py +206 -0
  548. pyfect/hash_set.py +163 -0
  549. pyfect/http/__init__.py +125 -0
  550. pyfect/http/_asgi_listener.py +272 -0
  551. pyfect/http/_authority.py +63 -0
  552. pyfect/http/_brotli.py +27 -0
  553. pyfect/http/_compression.py +52 -0
  554. pyfect/http/_field.py +18 -0
  555. pyfect/http/_foreign_path.py +27 -0
  556. pyfect/http/_form_data.py +34 -0
  557. pyfect/http/_httpx_options.py +120 -0
  558. pyfect/http/_in_memory.py +76 -0
  559. pyfect/http/_request_state.py +59 -0
  560. pyfect/http/_vary.py +14 -0
  561. pyfect/http/abort.py +65 -0
  562. pyfect/http/asgi/__init__.py +59 -0
  563. pyfect/http/asgi/_app.py +155 -0
  564. pyfect/http/asgi/_http.py +201 -0
  565. pyfect/http/asgi/_mount.py +263 -0
  566. pyfect/http/asgi/_scope.py +86 -0
  567. pyfect/http/asgi/_serve.py +72 -0
  568. pyfect/http/asgi/_types.py +13 -0
  569. pyfect/http/asgi/_web_socket.py +325 -0
  570. pyfect/http/body.py +437 -0
  571. pyfect/http/client/__init__.py +111 -0
  572. pyfect/http/client/_circuit_breaker.py +113 -0
  573. pyfect/http/client/_cookie_jar.py +120 -0
  574. pyfect/http/client/_make.py +252 -0
  575. pyfect/http/client/_rate_limit.py +423 -0
  576. pyfect/http/client/_redirects.py +93 -0
  577. pyfect/http/client/_retry.py +115 -0
  578. pyfect/http/client/_service.py +497 -0
  579. pyfect/http/cookies.py +444 -0
  580. pyfect/http/error.py +188 -0
  581. pyfect/http/etag.py +96 -0
  582. pyfect/http/file_like.py +49 -0
  583. pyfect/http/find_my_way/__init__.py +10 -0
  584. pyfect/http/find_my_way/_nodes.py +186 -0
  585. pyfect/http/find_my_way/_paths.py +43 -0
  586. pyfect/http/find_my_way/_query_string.py +67 -0
  587. pyfect/http/find_my_way/_router.py +401 -0
  588. pyfect/http/headers.py +343 -0
  589. pyfect/http/http_effect.py +198 -0
  590. pyfect/http/httpx_client.py +291 -0
  591. pyfect/http/hypercorn_server.py +122 -0
  592. pyfect/http/incoming_message.py +140 -0
  593. pyfect/http/live_server/__init__.py +191 -0
  594. pyfect/http/live_server/_body.py +164 -0
  595. pyfect/http/live_server/_exchange.py +321 -0
  596. pyfect/http/live_server/_head.py +194 -0
  597. pyfect/http/live_server/_inbound.py +156 -0
  598. pyfect/http/live_server/_listener.py +211 -0
  599. pyfect/http/live_server/_serve.py +225 -0
  600. pyfect/http/live_server/_timers.py +20 -0
  601. pyfect/http/live_server/_upgrade.py +108 -0
  602. pyfect/http/live_server/_websocket.py +286 -0
  603. pyfect/http/live_server/_ws_frames.py +242 -0
  604. pyfect/http/method.py +30 -0
  605. pyfect/http/middleware/__init__.py +61 -0
  606. pyfect/http/middleware/_compression.py +156 -0
  607. pyfect/http/middleware/_cors.py +129 -0
  608. pyfect/http/middleware/_decompression.py +274 -0
  609. pyfect/http/middleware/_forwarded.py +113 -0
  610. pyfect/http/middleware/_logger.py +73 -0
  611. pyfect/http/middleware/_search_params.py +34 -0
  612. pyfect/http/middleware/_tracer.py +153 -0
  613. pyfect/http/middleware/_types.py +16 -0
  614. pyfect/http/mime/__init__.py +69 -0
  615. pyfect/http/mime/_types.py +361 -0
  616. pyfect/http/multipart.py +613 -0
  617. pyfect/http/multipart_parser/__init__.py +348 -0
  618. pyfect/http/multipart_parser/_content_type.py +109 -0
  619. pyfect/http/multipart_parser/_headers.py +206 -0
  620. pyfect/http/multipart_parser/_search.py +85 -0
  621. pyfect/http/origin.py +146 -0
  622. pyfect/http/platform.py +593 -0
  623. pyfect/http/prometheus.py +34 -0
  624. pyfect/http/request.py +384 -0
  625. pyfect/http/response.py +474 -0
  626. pyfect/http/router/__init__.py +82 -0
  627. pyfect/http/router/_api.py +462 -0
  628. pyfect/http/router/_in_memory.py +76 -0
  629. pyfect/http/router/_markers.py +47 -0
  630. pyfect/http/router/_middleware.py +181 -0
  631. pyfect/http/router/_middleware_stack.py +51 -0
  632. pyfect/http/router/_provided.py +31 -0
  633. pyfect/http/router/_route.py +114 -0
  634. pyfect/http/router/_router.py +308 -0
  635. pyfect/http/schema.py +276 -0
  636. pyfect/http/server.py +199 -0
  637. pyfect/http/server_error.py +261 -0
  638. pyfect/http/server_request.py +729 -0
  639. pyfect/http/server_respondable.py +77 -0
  640. pyfect/http/server_response.py +569 -0
  641. pyfect/http/static_server/__init__.py +257 -0
  642. pyfect/http/static_server/_conditional.py +72 -0
  643. pyfect/http/static_server/_mime.py +55 -0
  644. pyfect/http/static_server/_range.py +53 -0
  645. pyfect/http/status.py +51 -0
  646. pyfect/http/template.py +161 -0
  647. pyfect/http/trace_context.py +91 -0
  648. pyfect/http/url.py +442 -0
  649. pyfect/http/url_params.py +304 -0
  650. pyfect/http/uvicorn_server.py +119 -0
  651. pyfect/http/web.py +171 -0
  652. pyfect/http/web_handler.py +463 -0
  653. pyfect/http/wire.py +209 -0
  654. pyfect/http_api/__init__.py +83 -0
  655. pyfect/http_api/_assets/scalar.js +8 -0
  656. pyfect/http_api/_assets/swagger-ui.css +3 -0
  657. pyfect/http_api/_assets/swagger-ui.js +4 -0
  658. pyfect/http_api/_client_method.py +220 -0
  659. pyfect/http_api/_client_payload.py +144 -0
  660. pyfect/http_api/_client_response.py +377 -0
  661. pyfect/http_api/_handlers.py +282 -0
  662. pyfect/http_api/_html.py +38 -0
  663. pyfect/http_api/_media_type.py +6 -0
  664. pyfect/http_api/_openapi_responses.py +164 -0
  665. pyfect/http_api/_openapi_schemas.py +163 -0
  666. pyfect/http_api/_path.py +102 -0
  667. pyfect/http_api/_payload.py +260 -0
  668. pyfect/http_api/_response.py +363 -0
  669. pyfect/http_api/_security.py +174 -0
  670. pyfect/http_api/api.py +265 -0
  671. pyfect/http_api/builder.py +447 -0
  672. pyfect/http_api/client.py +474 -0
  673. pyfect/http_api/endpoint.py +969 -0
  674. pyfect/http_api/error.py +280 -0
  675. pyfect/http_api/group.py +215 -0
  676. pyfect/http_api/middleware.py +232 -0
  677. pyfect/http_api/openapi.py +396 -0
  678. pyfect/http_api/scalar.py +143 -0
  679. pyfect/http_api/schema.py +713 -0
  680. pyfect/http_api/security.py +91 -0
  681. pyfect/http_api/swagger.py +69 -0
  682. pyfect/http_api/test.py +105 -0
  683. pyfect/json_patch.py +255 -0
  684. pyfect/json_pointer.py +100 -0
  685. pyfect/json_schema/__init__.py +66 -0
  686. pyfect/json_schema/_api.py +96 -0
  687. pyfect/json_schema/_converter.py +258 -0
  688. pyfect/json_schema/_draft04.py +198 -0
  689. pyfect/json_schema/_draft07.py +203 -0
  690. pyfect/json_schema/_keywords.py +202 -0
  691. pyfect/json_schema/_model.py +201 -0
  692. pyfect/json_schema/_openapi.py +208 -0
  693. pyfect/latch.py +127 -0
  694. pyfect/layer.py +479 -0
  695. pyfect/layer_map.py +279 -0
  696. pyfect/layer_ref.py +208 -0
  697. pyfect/logger/__init__.py +91 -0
  698. pyfect/logger/_batched.py +49 -0
  699. pyfect/logger/_console.py +116 -0
  700. pyfect/logger/_file.py +31 -0
  701. pyfect/logger/_formats.py +104 -0
  702. pyfect/logger/_layer.py +50 -0
  703. pyfect/logger/_level.py +53 -0
  704. pyfect/logger/_log.py +142 -0
  705. pyfect/logger/_model.py +163 -0
  706. pyfect/logger/_refs.py +78 -0
  707. pyfect/logger/_stdlib.py +54 -0
  708. pyfect/logger/_text.py +263 -0
  709. pyfect/logger/_tracer.py +35 -0
  710. pyfect/managed_runtime.py +393 -0
  711. pyfect/metric/__init__.py +119 -0
  712. pyfect/metric/_boundaries.py +27 -0
  713. pyfect/metric/_kinds.py +417 -0
  714. pyfect/metric/_metric.py +302 -0
  715. pyfect/metric/_prometheus.py +150 -0
  716. pyfect/metric/_refs.py +78 -0
  717. pyfect/metric/_runtime.py +75 -0
  718. pyfect/metric/_snapshot.py +97 -0
  719. pyfect/metric/_state.py +74 -0
  720. pyfect/msgspec.py +98 -0
  721. pyfect/mutable_hash_map.py +140 -0
  722. pyfect/mutable_hash_set.py +95 -0
  723. pyfect/net/__init__.py +18 -0
  724. pyfect/net/_errors.py +29 -0
  725. pyfect/net/address_resolver.py +179 -0
  726. pyfect/net/dns/__init__.py +92 -0
  727. pyfect/net/dns/_error.py +43 -0
  728. pyfect/net/dns/_records.py +335 -0
  729. pyfect/net/dns/_service.py +287 -0
  730. pyfect/net/dns/_system.py +89 -0
  731. pyfect/net/host.py +311 -0
  732. pyfect/net/ip_interface.py +202 -0
  733. pyfect/net/ip_network.py +250 -0
  734. pyfect/net/net_address/__init__.py +245 -0
  735. pyfect/net/net_address/_inet.py +412 -0
  736. pyfect/net/net_address/_ip.py +348 -0
  737. pyfect/net/net_address/_mac.py +119 -0
  738. pyfect/optic/__init__.py +50 -0
  739. pyfect/optic/_builtins.py +90 -0
  740. pyfect/optic/_data.py +97 -0
  741. pyfect/optic/_optic.py +422 -0
  742. pyfect/optic/_steps.py +151 -0
  743. pyfect/option.py +362 -0
  744. pyfect/otel/__init__.py +22 -0
  745. pyfect/otel/_attributes.py +67 -0
  746. pyfect/otel/_producer.py +322 -0
  747. pyfect/otel/_shutdown.py +26 -0
  748. pyfect/otel/_span.py +292 -0
  749. pyfect/otel/_wrapper.py +92 -0
  750. pyfect/otel/logger.py +154 -0
  751. pyfect/otel/metrics.py +126 -0
  752. pyfect/otel/resource.py +111 -0
  753. pyfect/otel/sdk.py +195 -0
  754. pyfect/otel/tracer.py +157 -0
  755. pyfect/partitioned_semaphore.py +211 -0
  756. pyfect/path.py +304 -0
  757. pyfect/persistence/__init__.py +77 -0
  758. pyfect/persistence/_columns.py +32 -0
  759. pyfect/persistence/_error.py +14 -0
  760. pyfect/persistence/_seconds.py +68 -0
  761. pyfect/persistence/_sql_keys.py +47 -0
  762. pyfect/persistence/circuit_breaker/__init__.py +120 -0
  763. pyfect/persistence/circuit_breaker/_breaker.py +317 -0
  764. pyfect/persistence/circuit_breaker/_errors.py +67 -0
  765. pyfect/persistence/circuit_breaker/_memory.py +243 -0
  766. pyfect/persistence/circuit_breaker/_redis.py +509 -0
  767. pyfect/persistence/circuit_breaker/_store.py +60 -0
  768. pyfect/persistence/circuit_breaker/_types.py +191 -0
  769. pyfect/persistence/key_value_store/__init__.py +51 -0
  770. pyfect/persistence/key_value_store/_layers.py +216 -0
  771. pyfect/persistence/key_value_store/_schema_store.py +91 -0
  772. pyfect/persistence/key_value_store/_sql.py +197 -0
  773. pyfect/persistence/key_value_store/_store.py +212 -0
  774. pyfect/persistence/persistable.py +164 -0
  775. pyfect/persistence/persisted_cache.py +159 -0
  776. pyfect/persistence/persisted_queue/__init__.py +75 -0
  777. pyfect/persistence/persisted_queue/_error.py +42 -0
  778. pyfect/persistence/persisted_queue/_mailbox.py +101 -0
  779. pyfect/persistence/persisted_queue/_memory.py +182 -0
  780. pyfect/persistence/persisted_queue/_queue.py +272 -0
  781. pyfect/persistence/persisted_queue/_redis.py +455 -0
  782. pyfect/persistence/persisted_queue/_redis_scripts.py +395 -0
  783. pyfect/persistence/persisted_queue/_sql.py +334 -0
  784. pyfect/persistence/persisted_queue/_sql_migrations.py +319 -0
  785. pyfect/persistence/persisted_queue/_sql_statements.py +441 -0
  786. pyfect/persistence/persisted_queue/_store.py +147 -0
  787. pyfect/persistence/persistence/__init__.py +84 -0
  788. pyfect/persistence/persistence/_kvs.py +135 -0
  789. pyfect/persistence/persistence/_memory.py +62 -0
  790. pyfect/persistence/persistence/_redis.py +162 -0
  791. pyfect/persistence/persistence/_service.py +276 -0
  792. pyfect/persistence/persistence/_sql.py +499 -0
  793. pyfect/persistence/rate_limiter/__init__.py +82 -0
  794. pyfect/persistence/rate_limiter/_errors.py +59 -0
  795. pyfect/persistence/rate_limiter/_limiter.py +325 -0
  796. pyfect/persistence/rate_limiter/_memory.py +217 -0
  797. pyfect/persistence/rate_limiter/_redis.py +485 -0
  798. pyfect/persistence/rate_limiter/_store.py +89 -0
  799. pyfect/persistence/redis/__init__.py +52 -0
  800. pyfect/persistence/redis/_error.py +12 -0
  801. pyfect/persistence/redis/_make.py +234 -0
  802. pyfect/persistence/redis/_script.py +78 -0
  803. pyfect/persistence/redis/_service.py +104 -0
  804. pyfect/persistence/redis_py.py +303 -0
  805. pyfect/persistence/user_directories.py +195 -0
  806. pyfect/platform.py +26 -0
  807. pyfect/platform_error.py +256 -0
  808. pyfect/pool/__init__.py +36 -0
  809. pyfect/pool/_pool.py +707 -0
  810. pyfect/pool/_state.py +161 -0
  811. pyfect/pool/_ttl.py +105 -0
  812. pyfect/pool/_waiters.py +116 -0
  813. pyfect/primary_key.py +35 -0
  814. pyfect/process/__init__.py +82 -0
  815. pyfect/process/_child.py +213 -0
  816. pyfect/process/_command.py +358 -0
  817. pyfect/process/_handle.py +77 -0
  818. pyfect/process/_live.py +455 -0
  819. pyfect/process/_os.py +78 -0
  820. pyfect/process/_pipes.py +291 -0
  821. pyfect/process/_spawner.py +75 -0
  822. pyfect/pubsub/__init__.py +33 -0
  823. pyfect/pubsub/_atomic.py +181 -0
  824. pyfect/pubsub/_hub.py +214 -0
  825. pyfect/pubsub/_pubsub.py +214 -0
  826. pyfect/pubsub/_replay.py +107 -0
  827. pyfect/pubsub/_subscription.py +226 -0
  828. pyfect/pull.py +132 -0
  829. pyfect/py.typed +0 -0
  830. pyfect/pydantic.py +188 -0
  831. pyfect/queue/__init__.py +33 -0
  832. pyfect/queue/_queue.py +525 -0
  833. pyfect/queue/_state.py +111 -0
  834. pyfect/queue/_views.py +55 -0
  835. pyfect/random.py +146 -0
  836. pyfect/rc_map.py +363 -0
  837. pyfect/rc_ref.py +271 -0
  838. pyfect/reactivity/__init__.py +53 -0
  839. pyfect/reactivity/_async_result_schema.py +227 -0
  840. pyfect/reactivity/_hydration.py +18 -0
  841. pyfect/reactivity/_live.py +21 -0
  842. pyfect/reactivity/_reactivity.py +256 -0
  843. pyfect/reactivity/_result_effect.py +17 -0
  844. pyfect/reactivity/_time.py +11 -0
  845. pyfect/reactivity/async_result.py +679 -0
  846. pyfect/reactivity/atom/__init__.py +143 -0
  847. pyfect/reactivity/atom/_combinators.py +223 -0
  848. pyfect/reactivity/atom/_constructors.py +80 -0
  849. pyfect/reactivity/atom/_conversions.py +79 -0
  850. pyfect/reactivity/atom/_effect.py +252 -0
  851. pyfect/reactivity/atom/_fn.py +341 -0
  852. pyfect/reactivity/atom/_kvs.py +101 -0
  853. pyfect/reactivity/atom/_optimistic.py +162 -0
  854. pyfect/reactivity/atom/_runtime.py +323 -0
  855. pyfect/reactivity/atom/_serializable.py +65 -0
  856. pyfect/reactivity/atom/_subscription_ref.py +102 -0
  857. pyfect/reactivity/atom/_swr.py +69 -0
  858. pyfect/reactivity/atom/_types.py +435 -0
  859. pyfect/reactivity/atom_http_api.py +667 -0
  860. pyfect/reactivity/atom_ref.py +260 -0
  861. pyfect/reactivity/atom_registry/__init__.py +219 -0
  862. pyfect/reactivity/atom_registry/_batch.py +96 -0
  863. pyfect/reactivity/atom_registry/_dispatcher.py +60 -0
  864. pyfect/reactivity/atom_registry/_lifetime.py +202 -0
  865. pyfect/reactivity/atom_registry/_node.py +423 -0
  866. pyfect/reactivity/atom_registry/_registry.py +380 -0
  867. pyfect/reactivity/atom_rpc.py +283 -0
  868. pyfect/reactivity/hydration.py +200 -0
  869. pyfect/redacted.py +83 -0
  870. pyfect/ref.py +129 -0
  871. pyfect/resource.py +98 -0
  872. pyfect/result.py +306 -0
  873. pyfect/rpc/__init__.py +64 -0
  874. pyfect/rpc/_encoded_schema.py +86 -0
  875. pyfect/rpc/_json_rpc.py +246 -0
  876. pyfect/rpc/_methods.py +177 -0
  877. pyfect/rpc/_rpc.py +498 -0
  878. pyfect/rpc/client/__init__.py +100 -0
  879. pyfect/rpc/client/_core.py +449 -0
  880. pyfect/rpc/client/_http.py +257 -0
  881. pyfect/rpc/client/_protocol.py +171 -0
  882. pyfect/rpc/client/_serialized.py +321 -0
  883. pyfect/rpc/client/_transports.py +328 -0
  884. pyfect/rpc/client/_worker.py +283 -0
  885. pyfect/rpc/client_error.py +35 -0
  886. pyfect/rpc/group.py +296 -0
  887. pyfect/rpc/message.py +299 -0
  888. pyfect/rpc/middleware.py +182 -0
  889. pyfect/rpc/schema.py +89 -0
  890. pyfect/rpc/serialization.py +366 -0
  891. pyfect/rpc/server/__init__.py +181 -0
  892. pyfect/rpc/server/_core.py +549 -0
  893. pyfect/rpc/server/_protocol.py +123 -0
  894. pyfect/rpc/server/_serialized.py +363 -0
  895. pyfect/rpc/server/_stdio.py +101 -0
  896. pyfect/rpc/server/_transports.py +427 -0
  897. pyfect/rpc/server/_worker.py +108 -0
  898. pyfect/rpc/test.py +74 -0
  899. pyfect/rpc/worker.py +92 -0
  900. pyfect/run.py +393 -0
  901. pyfect/schedule/__init__.py +91 -0
  902. pyfect/schedule/_combinators.py +168 -0
  903. pyfect/schedule/_constructors.py +223 -0
  904. pyfect/schedule/_cron.py +49 -0
  905. pyfect/schedule/_drive.py +191 -0
  906. pyfect/schedule/_model.py +405 -0
  907. pyfect/scheduler.py +575 -0
  908. pyfect/schema/__init__.py +866 -0
  909. pyfect/schema/_adapters.py +39 -0
  910. pyfect/schema/_arbitrary_constraint.py +242 -0
  911. pyfect/schema/_arbitrary_graph.py +325 -0
  912. pyfect/schema/_arbitrary_links.py +179 -0
  913. pyfect/schema/_arbitrary_number.py +112 -0
  914. pyfect/schema/_arrays.py +287 -0
  915. pyfect/schema/_assignable.py +118 -0
  916. pyfect/schema/_boolean_literals.py +31 -0
  917. pyfect/schema/_checks_number.py +216 -0
  918. pyfect/schema/_checks_order.py +140 -0
  919. pyfect/schema/_checks_size.py +277 -0
  920. pyfect/schema/_checks_string.py +241 -0
  921. pyfect/schema/_class.py +569 -0
  922. pyfect/schema/_codec_derivation.py +227 -0
  923. pyfect/schema/_codec_links.py +221 -0
  924. pyfect/schema/_codecs.py +316 -0
  925. pyfect/schema/_collections.py +172 -0
  926. pyfect/schema/_constructor_default.py +89 -0
  927. pyfect/schema/_data.py +440 -0
  928. pyfect/schema/_data_codecs.py +145 -0
  929. pyfect/schema/_decimal_regexp.py +243 -0
  930. pyfect/schema/_declare.py +68 -0
  931. pyfect/schema/_derive.py +292 -0
  932. pyfect/schema/_duration_codecs.py +27 -0
  933. pyfect/schema/_ecma_pattern.py +416 -0
  934. pyfect/schema/_error.py +26 -0
  935. pyfect/schema/_error_instance.py +222 -0
  936. pyfect/schema/_graph.py +271 -0
  937. pyfect/schema/_instances.py +240 -0
  938. pyfect/schema/_jsonschema/__init__.py +90 -0
  939. pyfect/schema/_jsonschema/_annotations.py +114 -0
  940. pyfect/schema/_jsonschema/_checks.py +253 -0
  941. pyfect/schema/_jsonschema/_compile.py +346 -0
  942. pyfect/schema/_jsonschema/_exact.py +19 -0
  943. pyfect/schema/_jsonschema/_merge.py +211 -0
  944. pyfect/schema/_jsonschema/_objects.py +231 -0
  945. pyfect/schema/_jsonschema/_references.py +221 -0
  946. pyfect/schema/_jsonschema/_template.py +69 -0
  947. pyfect/schema/_literals.py +147 -0
  948. pyfect/schema/_middleware.py +209 -0
  949. pyfect/schema/_net.py +522 -0
  950. pyfect/schema/_options.py +49 -0
  951. pyfect/schema/_parse.py +351 -0
  952. pyfect/schema/_parsed_text.py +37 -0
  953. pyfect/schema/_primitives.py +48 -0
  954. pyfect/schema/_record.py +41 -0
  955. pyfect/schema/_refine.py +81 -0
  956. pyfect/schema/_schema.py +158 -0
  957. pyfect/schema/_semver.py +144 -0
  958. pyfect/schema/_strategy/__init__.py +258 -0
  959. pyfect/schema/_strategy/_big_decimal.py +203 -0
  960. pyfect/schema/_strategy/_composites.py +119 -0
  961. pyfect/schema/_strategy/_leaves.py +94 -0
  962. pyfect/schema/_strategy/_net.py +133 -0
  963. pyfect/schema/_struct.py +87 -0
  964. pyfect/schema/_struct_keys.py +128 -0
  965. pyfect/schema/_tagged.py +254 -0
  966. pyfect/schema/_template_literal.py +172 -0
  967. pyfect/schema/_to_codec_array_from_single.py +115 -0
  968. pyfect/schema/_to_codec_go_json.py +174 -0
  969. pyfect/schema/_to_codec_json.py +73 -0
  970. pyfect/schema/_to_codec_string_tree.py +115 -0
  971. pyfect/schema/_to_differ_json_patch.py +44 -0
  972. pyfect/schema/_to_encoder_xml.py +119 -0
  973. pyfect/schema/_to_equivalence.py +186 -0
  974. pyfect/schema/_to_formatter.py +180 -0
  975. pyfect/schema/_to_iso.py +73 -0
  976. pyfect/schema/_to_strategy.py +31 -0
  977. pyfect/schema/_transform.py +210 -0
  978. pyfect/schema/_tree.py +27 -0
  979. pyfect/schema/_type_walk.py +53 -0
  980. pyfect/schema/_undefined.py +58 -0
  981. pyfect/schema/_value_codecs.py +84 -0
  982. pyfect/schema/_values.py +123 -0
  983. pyfect/schema/_void.py +86 -0
  984. pyfect/schema/ast/__init__.py +227 -0
  985. pyfect/schema/ast/_annotations.py +43 -0
  986. pyfect/schema/ast/_arrays.py +210 -0
  987. pyfect/schema/ast/_base.py +295 -0
  988. pyfect/schema/ast/_candidates.py +309 -0
  989. pyfect/schema/ast/_check.py +181 -0
  990. pyfect/schema/ast/_class.py +159 -0
  991. pyfect/schema/ast/_constructors.py +65 -0
  992. pyfect/schema/ast/_declaration.py +97 -0
  993. pyfect/schema/ast/_encoding.py +111 -0
  994. pyfect/schema/ast/_json.py +129 -0
  995. pyfect/schema/ast/_keywords.py +125 -0
  996. pyfect/schema/ast/_literal.py +157 -0
  997. pyfect/schema/ast/_objects.py +356 -0
  998. pyfect/schema/ast/_record.py +36 -0
  999. pyfect/schema/ast/_result.py +116 -0
  1000. pyfect/schema/ast/_steps.py +209 -0
  1001. pyfect/schema/ast/_suspend.py +65 -0
  1002. pyfect/schema/ast/_template_literal.py +256 -0
  1003. pyfect/schema/ast/_union.py +172 -0
  1004. pyfect/schema/getter/__init__.py +136 -0
  1005. pyfect/schema/getter/_binary.py +104 -0
  1006. pyfect/schema/getter/_coerce.py +196 -0
  1007. pyfect/schema/getter/_getter.py +243 -0
  1008. pyfect/schema/getter/_make.py +151 -0
  1009. pyfect/schema/getter/_text.py +141 -0
  1010. pyfect/schema/getter/_tree_record.py +170 -0
  1011. pyfect/schema/issue.py +420 -0
  1012. pyfect/schema/model/__init__.py +120 -0
  1013. pyfect/schema/model/_class.py +245 -0
  1014. pyfect/schema/model/_dates.py +103 -0
  1015. pyfect/schema/model/_fields.py +77 -0
  1016. pyfect/schema/model/_toolkit.py +114 -0
  1017. pyfect/schema/model/_uuid.py +69 -0
  1018. pyfect/schema/representation/__init__.py +424 -0
  1019. pyfect/schema/representation/_builtin_revivers.py +331 -0
  1020. pyfect/schema/representation/_code.py +106 -0
  1021. pyfect/schema/representation/_code_builtins.py +281 -0
  1022. pyfect/schema/representation/_code_document.py +563 -0
  1023. pyfect/schema/representation/_code_sort.py +111 -0
  1024. pyfect/schema/representation/_from.py +278 -0
  1025. pyfect/schema/representation/_import/__init__.py +78 -0
  1026. pyfect/schema/representation/_import/_finalize.py +121 -0
  1027. pyfect/schema/representation/_import/_intersect.py +467 -0
  1028. pyfect/schema/representation/_import/_js_order.py +66 -0
  1029. pyfect/schema/representation/_import/_keywords.py +224 -0
  1030. pyfect/schema/representation/_import/_nodes.py +199 -0
  1031. pyfect/schema/representation/_import/_translate.py +455 -0
  1032. pyfect/schema/representation/_json.py +520 -0
  1033. pyfect/schema/representation/_json_schema.py +178 -0
  1034. pyfect/schema/representation/_model.py +284 -0
  1035. pyfect/schema/representation/_revivers.py +89 -0
  1036. pyfect/schema/representation/_to.py +249 -0
  1037. pyfect/schema/transformation/__init__.py +99 -0
  1038. pyfect/schema/transformation/_builtins.py +314 -0
  1039. pyfect/schema/transformation/_durations.py +150 -0
  1040. pyfect/schema/transformation/_transformation.py +177 -0
  1041. pyfect/schema/variant_schema/__init__.py +69 -0
  1042. pyfect/schema/variant_schema/_class.py +188 -0
  1043. pyfect/schema/variant_schema/_defaults.py +30 -0
  1044. pyfect/schema/variant_schema/_field.py +32 -0
  1045. pyfect/schema/variant_schema/_struct.py +130 -0
  1046. pyfect/schema/variant_schema/_toolkit.py +160 -0
  1047. pyfect/scope.py +374 -0
  1048. pyfect/scoped_ref.py +124 -0
  1049. pyfect/semaphore.py +276 -0
  1050. pyfect/semver.py +403 -0
  1051. pyfect/semver_range.py +420 -0
  1052. pyfect/sink/__init__.py +131 -0
  1053. pyfect/sink/_combinators.py +151 -0
  1054. pyfect/sink/_constructors.py +187 -0
  1055. pyfect/sink/_context.py +87 -0
  1056. pyfect/sink/_folds.py +336 -0
  1057. pyfect/sink/_for_each.py +87 -0
  1058. pyfect/sink/_sink.py +265 -0
  1059. pyfect/sink/_steps.py +34 -0
  1060. pyfect/sink/_taking.py +183 -0
  1061. pyfect/socket/__init__.py +146 -0
  1062. pyfect/socket/_accepted.py +65 -0
  1063. pyfect/socket/_connection.py +384 -0
  1064. pyfect/socket/_errors.py +135 -0
  1065. pyfect/socket/_loop.py +66 -0
  1066. pyfect/socket/_net.py +281 -0
  1067. pyfect/socket/_socket.py +245 -0
  1068. pyfect/socket/_tls.py +88 -0
  1069. pyfect/socket/_tls_session.py +117 -0
  1070. pyfect/socket/_web_socket.py +555 -0
  1071. pyfect/socket/datagram/__init__.py +110 -0
  1072. pyfect/socket/datagram/_core.py +460 -0
  1073. pyfect/socket/datagram/_errors.py +102 -0
  1074. pyfect/socket/datagram/_live.py +675 -0
  1075. pyfect/socket/datagram/_model.py +217 -0
  1076. pyfect/socket/server.py +258 -0
  1077. pyfect/socket/ws.py +484 -0
  1078. pyfect/sql/__init__.py +60 -0
  1079. pyfect/sql/_loop.py +134 -0
  1080. pyfect/sql/clickhouse/__init__.py +74 -0
  1081. pyfect/sql/clickhouse/_connection.py +237 -0
  1082. pyfect/sql/clickhouse/_rows.py +87 -0
  1083. pyfect/sql/clickhouse/client.py +322 -0
  1084. pyfect/sql/clickhouse/config.py +241 -0
  1085. pyfect/sql/clickhouse/driver.py +434 -0
  1086. pyfect/sql/clickhouse/error.py +106 -0
  1087. pyfect/sql/clickhouse/migrator.py +47 -0
  1088. pyfect/sql/clickhouse/params.py +168 -0
  1089. pyfect/sql/client/__init__.py +35 -0
  1090. pyfect/sql/client/_client.py +309 -0
  1091. pyfect/sql/client/_sqlite_acquirers.py +130 -0
  1092. pyfect/sql/client/_transaction.py +410 -0
  1093. pyfect/sql/connection.py +87 -0
  1094. pyfect/sql/d1/__init__.py +48 -0
  1095. pyfect/sql/d1/api.py +270 -0
  1096. pyfect/sql/d1/client.py +344 -0
  1097. pyfect/sql/d1/config.py +55 -0
  1098. pyfect/sql/error.py +311 -0
  1099. pyfect/sql/libsql/__init__.py +58 -0
  1100. pyfect/sql/libsql/_connection.py +110 -0
  1101. pyfect/sql/libsql/_hrana.py +258 -0
  1102. pyfect/sql/libsql/_local.py +251 -0
  1103. pyfect/sql/libsql/_targets.py +28 -0
  1104. pyfect/sql/libsql/_values.py +46 -0
  1105. pyfect/sql/libsql/client.py +225 -0
  1106. pyfect/sql/libsql/config.py +170 -0
  1107. pyfect/sql/libsql/migrator.py +43 -0
  1108. pyfect/sql/libsql/sdk.py +123 -0
  1109. pyfect/sql/migrator.py +434 -0
  1110. pyfect/sql/model.py +324 -0
  1111. pyfect/sql/mssql/__init__.py +79 -0
  1112. pyfect/sql/mssql/_connection.py +169 -0
  1113. pyfect/sql/mssql/_driver.py +103 -0
  1114. pyfect/sql/mssql/_names.py +9 -0
  1115. pyfect/sql/mssql/_pool.py +125 -0
  1116. pyfect/sql/mssql/_tds.py +447 -0
  1117. pyfect/sql/mssql/_tds_params.py +155 -0
  1118. pyfect/sql/mssql/_worker.py +155 -0
  1119. pyfect/sql/mssql/client.py +344 -0
  1120. pyfect/sql/mssql/config.py +118 -0
  1121. pyfect/sql/mssql/error.py +111 -0
  1122. pyfect/sql/mssql/migrator.py +43 -0
  1123. pyfect/sql/mssql/parameter.py +44 -0
  1124. pyfect/sql/mssql/procedure.py +119 -0
  1125. pyfect/sql/mssql/types.py +137 -0
  1126. pyfect/sql/mysql/__init__.py +60 -0
  1127. pyfect/sql/mysql/_asyncmy.py +168 -0
  1128. pyfect/sql/mysql/_bind.py +76 -0
  1129. pyfect/sql/mysql/_connection.py +156 -0
  1130. pyfect/sql/mysql/_pool.py +63 -0
  1131. pyfect/sql/mysql/_session.py +262 -0
  1132. pyfect/sql/mysql/client.py +244 -0
  1133. pyfect/sql/mysql/config.py +108 -0
  1134. pyfect/sql/mysql/error.py +104 -0
  1135. pyfect/sql/mysql/migrator.py +44 -0
  1136. pyfect/sql/pg/__init__.py +82 -0
  1137. pyfect/sql/pg/_resolve.py +284 -0
  1138. pyfect/sql/pg/_session.py +380 -0
  1139. pyfect/sql/pg/client.py +398 -0
  1140. pyfect/sql/pg/config.py +142 -0
  1141. pyfect/sql/pg/connection.py +585 -0
  1142. pyfect/sql/pg/error.py +131 -0
  1143. pyfect/sql/pg/migrator.py +139 -0
  1144. pyfect/sql/pg/pool.py +265 -0
  1145. pyfect/sql/resolver.py +294 -0
  1146. pyfect/sql/result.py +24 -0
  1147. pyfect/sql/schema.py +116 -0
  1148. pyfect/sql/sqlite/__init__.py +26 -0
  1149. pyfect/sql/sqlite/_connection.py +230 -0
  1150. pyfect/sql/sqlite/_worker.py +71 -0
  1151. pyfect/sql/sqlite/client.py +248 -0
  1152. pyfect/sql/sqlite/migrator.py +43 -0
  1153. pyfect/sql/statement/__init__.py +144 -0
  1154. pyfect/sql/statement/_compiler.py +384 -0
  1155. pyfect/sql/statement/_segments.py +487 -0
  1156. pyfect/sql/statement/_statement.py +526 -0
  1157. pyfect/sql/statement/_transforms.py +93 -0
  1158. pyfect/sql/stream.py +88 -0
  1159. pyfect/stdio.py +206 -0
  1160. pyfect/stream/__init__.py +151 -0
  1161. pyfect/stream/_async_iterable.py +129 -0
  1162. pyfect/stream/_base.py +69 -0
  1163. pyfect/stream/_bridge_methods.py +139 -0
  1164. pyfect/stream/_catch.py +135 -0
  1165. pyfect/stream/_catch_reason.py +558 -0
  1166. pyfect/stream/_channel_methods.py +61 -0
  1167. pyfect/stream/_chunk_methods.py +169 -0
  1168. pyfect/stream/_chunking.py +310 -0
  1169. pyfect/stream/_concat.py +65 -0
  1170. pyfect/stream/_constructors.py +341 -0
  1171. pyfect/stream/_context.py +147 -0
  1172. pyfect/stream/_error_methods.py +254 -0
  1173. pyfect/stream/_execution_plan.py +199 -0
  1174. pyfect/stream/_fanout.py +154 -0
  1175. pyfect/stream/_fanout_methods.py +183 -0
  1176. pyfect/stream/_filter_methods.py +203 -0
  1177. pyfect/stream/_grouping.py +168 -0
  1178. pyfect/stream/_many.py +65 -0
  1179. pyfect/stream/_map_methods.py +233 -0
  1180. pyfect/stream/_mapping.py +126 -0
  1181. pyfect/stream/_run.py +114 -0
  1182. pyfect/stream/_run_methods.py +114 -0
  1183. pyfect/stream/_service_methods.py +36 -0
  1184. pyfect/stream/_sink_methods.py +151 -0
  1185. pyfect/stream/_sinking.py +277 -0
  1186. pyfect/stream/_sources.py +124 -0
  1187. pyfect/stream/_stream.py +162 -0
  1188. pyfect/stream/_taking.py +330 -0
  1189. pyfect/stream/_text.py +43 -0
  1190. pyfect/stream/_timing.py +294 -0
  1191. pyfect/stream/_timing_methods.py +252 -0
  1192. pyfect/stream/_zip_methods.py +279 -0
  1193. pyfect/stream/_zipping.py +213 -0
  1194. pyfect/subscription_ref.py +66 -0
  1195. pyfect/synchronized_ref.py +38 -0
  1196. pyfect/take.py +36 -0
  1197. pyfect/terminal/__init__.py +41 -0
  1198. pyfect/terminal/_keys.py +113 -0
  1199. pyfect/terminal/_live.py +223 -0
  1200. pyfect/terminal/_service.py +73 -0
  1201. pyfect/testing/__init__.py +122 -0
  1202. pyfect/testing/_assertions.py +92 -0
  1203. pyfect/testing/_clock.py +309 -0
  1204. pyfect/testing/_console.py +164 -0
  1205. pyfect/testing/_crypto.py +44 -0
  1206. pyfect/testing/_decorators.py +211 -0
  1207. pyfect/testing/_flaky.py +34 -0
  1208. pyfect/testing/_layers.py +153 -0
  1209. pyfect/testing/_prop.py +255 -0
  1210. pyfect/testing/_runners.py +84 -0
  1211. pyfect/testing/_runtime.py +174 -0
  1212. pyfect/testing/_schema.py +238 -0
  1213. pyfect/testing/plugin.py +59 -0
  1214. pyfect/tracer/__init__.py +107 -0
  1215. pyfect/tracer/_model.py +176 -0
  1216. pyfect/tracer/_native.py +172 -0
  1217. pyfect/tracer/_refs.py +87 -0
  1218. pyfect/tracer/_spans.py +269 -0
  1219. pyfect/transaction.py +340 -0
  1220. pyfect/trie.py +317 -0
  1221. pyfect/tx_chunk.py +127 -0
  1222. pyfect/tx_deferred.py +75 -0
  1223. pyfect/tx_hash_map.py +265 -0
  1224. pyfect/tx_hash_set.py +151 -0
  1225. pyfect/tx_priority_queue.py +224 -0
  1226. pyfect/tx_pubsub.py +194 -0
  1227. pyfect/tx_queue/__init__.py +27 -0
  1228. pyfect/tx_queue/_queue.py +359 -0
  1229. pyfect/tx_queue/_views.py +60 -0
  1230. pyfect/tx_reentrant_lock.py +201 -0
  1231. pyfect/tx_ref.py +79 -0
  1232. pyfect/tx_semaphore.py +136 -0
  1233. pyfect/tx_subscription_ref.py +118 -0
  1234. pyfect/workers/__init__.py +62 -0
  1235. pyfect/workers/_frames.py +82 -0
  1236. pyfect/workers/_mailbox.py +51 -0
  1237. pyfect/workers/_port.py +106 -0
  1238. pyfect/workers/_process.py +155 -0
  1239. pyfect/workers/_thread.py +100 -0
  1240. pyfect/workers/python_worker.py +133 -0
  1241. pyfect/workers/python_worker_runner.py +112 -0
  1242. pyfect/workers/transferable.py +103 -0
  1243. pyfect/workers/worker.py +273 -0
  1244. pyfect/workers/worker_error.py +86 -0
  1245. pyfect/workers/worker_runner.py +85 -0
  1246. pyfect/workflow/__init__.py +78 -0
  1247. pyfect/workflow/_crypto.py +23 -0
  1248. pyfect/workflow/_encoded.py +381 -0
  1249. pyfect/workflow/_memory.py +424 -0
  1250. pyfect/workflow/_result.py +43 -0
  1251. pyfect/workflow/_services.py +241 -0
  1252. pyfect/workflow/_suspension.py +153 -0
  1253. pyfect/workflow/activity.py +427 -0
  1254. pyfect/workflow/durable_clock.py +72 -0
  1255. pyfect/workflow/durable_deferred.py +403 -0
  1256. pyfect/workflow/durable_queue.py +259 -0
  1257. pyfect/workflow/workflow.py +509 -0
  1258. pyfect/workflow/workflow_engine.py +42 -0
  1259. pyfect/workflow/workflow_proxy.py +161 -0
  1260. pyfect/workflow/workflow_proxy_server.py +146 -0
  1261. pyfect_dev-0.1.0.dist-info/METADATA +296 -0
  1262. pyfect_dev-0.1.0.dist-info/RECORD +1265 -0
  1263. pyfect_dev-0.1.0.dist-info/WHEEL +4 -0
  1264. pyfect_dev-0.1.0.dist-info/entry_points.txt +3 -0
  1265. pyfect_dev-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1077 @@
1
+ """Generating text, objects and streams with a language model (Effect's
2
+ ``LanguageModel``).
3
+
4
+ A provider implements ``make``'s two functions, from ``ProviderOptions`` to
5
+ encoded response parts; the service decodes them, runs the tool calls the
6
+ model made with the toolkit's handlers and returns the parts::
7
+
8
+ response = yield from language_model.generate_text(
9
+ "What is the weather in Paris?", toolkit=toolkit
10
+ )
11
+ for part in response.tool_results:
12
+ match part:
13
+ case ToolResultSuccess(name="GetWeather", result=weather): ...
14
+
15
+ ``generate_object`` asks for JSON and decodes it with a schema;
16
+ ``stream_text`` streams the parts as they come, the tool results after the
17
+ model's parts.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from collections.abc import Callable, Mapping, Sequence
23
+ from dataclasses import dataclass, field, replace
24
+ from typing import TYPE_CHECKING, Any, Literal, LiteralString, Never, TypedDict, cast, overload
25
+
26
+ import pyfect as fx
27
+ from pyfect import _json_text
28
+ from pyfect import schema as S
29
+ from pyfect._core import Effect
30
+ from pyfect._effect_args import require_effect
31
+ from pyfect.ai import _approvals as A
32
+ from pyfect.ai import _tool_call_ids as Ids
33
+ from pyfect.ai import prompt as P
34
+ from pyfect.ai import response as R
35
+ from pyfect.ai import toolkit as K
36
+ from pyfect.ai._stream_resolution import (
37
+ incomplete_reason,
38
+ interrupted_result,
39
+ resolve_stream,
40
+ result_part,
41
+ )
42
+ from pyfect.ai.ai_error import (
43
+ AiError,
44
+ InvalidOutputError,
45
+ InvalidRequestError,
46
+ StructuredOutputError,
47
+ UnsupportedSchemaError,
48
+ )
49
+ from pyfect.ai.id_generator import IdGenerator, default_id_generator
50
+ from pyfect.ai.id_generator import Service as IdService
51
+ from pyfect.ai.response_id_tracker import ResponseIdTracker
52
+ from pyfect.ai.response_id_tracker import Service as Tracker
53
+ from pyfect.ai.tool import AnyTool, CodecTransformer
54
+ from pyfect.context import Tag
55
+ from pyfect.json_schema._model import JsonSchema
56
+ from pyfect.schema import SchemaError
57
+ from pyfect.stream import Stream
58
+ from pyfect.stream import _constructors as StreamC
59
+ from pyfect.stream._many import merge_all
60
+ from pyfect.tracer import Span
61
+
62
+ if TYPE_CHECKING:
63
+ from pyfect._concurrency import Concurrency
64
+
65
+
66
+ class ToolChoiceTool(TypedDict):
67
+ tool: str
68
+
69
+
70
+ class ToolChoiceOneOf(TypedDict, total=False):
71
+ one_of: Sequence[str]
72
+ mode: Literal["auto", "required"]
73
+
74
+
75
+ type ToolChoice = Literal["auto", "none", "required"] | ToolChoiceTool | ToolChoiceOneOf
76
+ """Which tools the model may call: any (``"auto"``), none, at least one,
77
+ ``{"tool": name}`` or ``{"one_of": names, "mode": ...}``."""
78
+
79
+
80
+ type ToolCallValidation = Literal["strict", "deferred"]
81
+ """How tool calls are checked with ``disable_tool_call_resolution``:
82
+ ``"strict"`` decodes each against its tool; ``"deferred"`` returns them as
83
+ the provider sent them, calls to tools outside the toolkit included (a
84
+ provider-executed call is still checked)."""
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class TextFormat:
89
+ type: Literal["text"] = "text"
90
+
91
+
92
+ @dataclass(frozen=True)
93
+ class JsonFormat:
94
+ object_name: str
95
+ schema: S.Top
96
+ type: Literal["json"] = "json"
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class ProviderOptions:
101
+ """What a provider gets: the prompt, the tools, the response format
102
+ and tool choice, the request's span and, for a conversation the
103
+ provider keeps, the previous response's id and the prompt after it."""
104
+
105
+ prompt: P.Prompt
106
+ tools: tuple[AnyTool, ...] = ()
107
+ response_format: TextFormat | JsonFormat = TextFormat()
108
+ tool_choice: ToolChoice = "none"
109
+ span: Span | None = None
110
+ previous_response_id: str | None = None
111
+ incremental_prompt: P.Prompt | None = None
112
+ incremental_fallback: bool = False
113
+ tool_call_validation: ToolCallValidation = "strict"
114
+
115
+
116
+ type EncodedPart = Mapping[str, object]
117
+ type GenerateFn = Callable[[ProviderOptions], Effect[Sequence[EncodedPart], AiError, Any]]
118
+ type StreamFn = Callable[[ProviderOptions], Stream[EncodedPart, AiError, Any]]
119
+
120
+
121
+ @dataclass(frozen=True)
122
+ class GenerateTextResponse[NN: str, RP]:
123
+ """A generated response: its parts, with accessors."""
124
+
125
+ content: Sequence[R.Part[NN, RP]]
126
+
127
+ @property
128
+ def text(self) -> str:
129
+ return "".join(part.text for part in self.content if isinstance(part, R.TextPart))
130
+
131
+ @property
132
+ def reasoning(self) -> list[R.ReasoningPart]:
133
+ return [part for part in self.content if isinstance(part, R.ReasoningPart)]
134
+
135
+ @property
136
+ def reasoning_text(self) -> str | None:
137
+ texts = [part.text for part in self.reasoning]
138
+ return "".join(texts) if texts else None
139
+
140
+ @property
141
+ def tool_calls(self) -> list[R.ToolCallPart[NN, object]]:
142
+ return [part for part in self.content if isinstance(part, R.ToolCallPart)]
143
+
144
+ @property
145
+ def tool_results(self) -> list[RP]:
146
+ return [
147
+ cast("RP", part)
148
+ for part in self.content
149
+ if isinstance(part, R.ToolResultSuccess | R.ToolResultFailure)
150
+ ]
151
+
152
+ @property
153
+ def finish_reason(self) -> R.FinishReason:
154
+ finish = self._finish()
155
+ return "unknown" if finish is None else finish.reason
156
+
157
+ @property
158
+ def usage(self) -> R.Usage:
159
+ finish = self._finish()
160
+ return R.Usage() if finish is None else finish.usage
161
+
162
+ def _finish(self) -> R.FinishPart | None:
163
+ return next((part for part in self.content if isinstance(part, R.FinishPart)), None)
164
+
165
+
166
+ @dataclass(frozen=True)
167
+ class GenerateObjectResponse[NN: str, RP, A](GenerateTextResponse[NN, RP]):
168
+ """A generated response with its decoded ``value``."""
169
+
170
+ value: A
171
+
172
+
173
+ def default_codec_transformer(schema: S.Top) -> tuple[S.Top, JsonSchema]:
174
+ """``schema`` itself and its JSON Schema, a top-level ``$ref``
175
+ resolved."""
176
+ document = S.to_json_schema_document(schema)
177
+ root: JsonSchema = dict(document.schema)
178
+ ref = root.get("$ref")
179
+ if isinstance(ref, str):
180
+ key = ref.removeprefix("#/$defs/")
181
+ root = dict(document.definitions[key])
182
+ if document.definitions:
183
+ root["$defs"] = dict(document.definitions)
184
+ return schema, root
185
+
186
+
187
+ def get_object_name(object_name: str | None, schema: S.Top) -> str:
188
+ """``object_name``, else the schema's identifier, else
189
+ ``"generateObject"``."""
190
+ if object_name is not None:
191
+ return object_name
192
+ identifier = (schema.__codec__().ast.annotations or {}).get("identifier")
193
+ return identifier if isinstance(identifier, str) else "generateObject"
194
+
195
+
196
+ def _tool_choice_attribute(tool_choice: ToolChoice) -> str:
197
+ """Effect's span attribute: the choice, an object one as JSON."""
198
+ if isinstance(tool_choice, str):
199
+ return tool_choice
200
+ if "tool" in tool_choice:
201
+ return _json_text.stringify(tool_choice)
202
+ choice = tool_choice
203
+ encoded: dict[str, object] = {}
204
+ if "mode" in choice:
205
+ encoded["mode"] = choice["mode"]
206
+ encoded["oneOf"] = list(choice.get("one_of", ()))
207
+ return _json_text.stringify(encoded)
208
+
209
+
210
+ def _error(method: str, reason: Any) -> AiError:
211
+ return AiError(module="LanguageModel", method=method, reason=reason)
212
+
213
+
214
+ def _incomplete_reason(parts: Sequence[EncodedPart]) -> str | None:
215
+ return incomplete_reason([part.get("reason") for part in parts if part.get("type") == "finish"])
216
+
217
+
218
+ def _annotate(
219
+ span: Span, output_type: str, tool_choice: ToolChoice, concurrency: Concurrency
220
+ ) -> None:
221
+ """Effect's ``annotateRequestOptions``."""
222
+ span.attribute("gen_ai.output.type", output_type)
223
+ span.attribute("effect.ai.tool_choice", _tool_choice_attribute(tool_choice))
224
+ span.attribute("effect.ai.concurrency", "unbounded" if concurrency is None else concurrency)
225
+
226
+
227
+ _UNDECLARED_TOOL_CALL = R.tool_call_part_schema(S.String, S.Unknown)
228
+
229
+
230
+ def _validation(disable: bool, validation: ToolCallValidation) -> ToolCallValidation:
231
+ """Validation is deferred only with tool call resolution disabled."""
232
+ return validation if disable else "strict"
233
+
234
+
235
+ def _decoded_toolkit(kit: K.WithHandler[Any, Any, Any, Any], encoded: bool) -> K.AnyToolkit:
236
+ tools = [
237
+ tool.set_parameters(S.to_encoded(tool.parameters_schema) if encoded else S.Unknown)
238
+ for tool in kit.tools.values()
239
+ ]
240
+ return K.make(*tools)
241
+
242
+
243
+ def _tool_calls(parts: Sequence[EncodedPart]) -> list[EncodedPart]:
244
+ return [
245
+ part
246
+ for part in parts
247
+ if part.get("type") == "tool-call" and part.get("providerExecuted") is not True
248
+ ]
249
+
250
+
251
+ def _resolve(
252
+ kit: K.WithHandler[Any, Any, Any, Any],
253
+ calls: Sequence[EncodedPart],
254
+ messages: Sequence[P.Message],
255
+ concurrency: Concurrency,
256
+ ) -> Stream[R.AnyToolResultPart | R.ToolApprovalRequestPart, Any, Any]:
257
+ """Each call's results: ``execution-denied`` when the user denied it,
258
+ the handler's when approved or not needing approval, else an approval
259
+ request."""
260
+ approvals = A.collect(messages)
261
+ approved = {approval.tool_call_id for approval in approvals.approved}
262
+ denied = {approval.tool_call_id: approval for approval in approvals.denied}
263
+
264
+ def handle(id: str, name: str, call: EncodedPart) -> Stream[R.AnyToolResultPart, Any, Any]:
265
+ handled = kit.handle(name, call.get("params"), id)
266
+ return StreamC.unwrap(handled).map(lambda result: result_part(id, name, result))
267
+
268
+ def run(call: EncodedPart) -> Stream[Any, Any, Any]:
269
+ id, name = cast("str", call["id"]), cast("str", call["name"])
270
+ tool = kit.tools.get(name)
271
+ if tool is None:
272
+ return StreamC.empty
273
+ if id in denied:
274
+ return StreamC.make(A.denied_result(id, name, denied[id].reason))
275
+ if id in approved:
276
+ return handle(id, name, call)
277
+ return StreamC.unwrap(
278
+ A.needs_approval(tool, call, messages).flat_map(
279
+ lambda needed: (
280
+ _approval_request(id).map(StreamC.make)
281
+ if needed
282
+ else fx.succeed(handle(id, name, call))
283
+ )
284
+ )
285
+ )
286
+
287
+ return merge_all([run(call) for call in calls], concurrency=concurrency)
288
+
289
+
290
+ def _approval_request(tool_call_id: str) -> Effect[R.ToolApprovalRequestPart, Never, IdGenerator]:
291
+ return IdGenerator().flat_map(
292
+ lambda generator: generator.generate_id().map(
293
+ lambda approval_id: R.ToolApprovalRequestPart(
294
+ approval_id=approval_id, tool_call_id=tool_call_id
295
+ )
296
+ )
297
+ )
298
+
299
+
300
+ def _validate_provider_executed(
301
+ kit: K.WithHandler[Any, Any, Any, Any], parts: Sequence[EncodedPart], encoded: bool = False
302
+ ) -> Effect[None, SchemaError]:
303
+ checks: list[Effect[object, SchemaError]] = []
304
+ for part in parts:
305
+ if part.get("type") != "tool-call" or part.get("providerExecuted") is not True:
306
+ continue
307
+ tool = kit.tools.get(cast("str", part.get("name")))
308
+ if tool is not None:
309
+ params = S.to_encoded(tool.parameters_schema) if encoded else tool.parameters_schema
310
+ decode = cast("Any", S.decode_unknown_effect(params))
311
+ checks.append(decode(part.get("params")))
312
+ return fx.for_each(checks, lambda check: check).as_(None)
313
+
314
+
315
+ def _mark(tracker: Tracker | None, prompt: P.Prompt, parts: Sequence[object]) -> None:
316
+ """Mark ``prompt``'s messages as sent with each response id in
317
+ ``parts`` (a stream chunk)."""
318
+ if tracker is None:
319
+ return
320
+ for part in parts:
321
+ if isinstance(part, R.ResponseMetadataPart) and part.id is not None:
322
+ tracker.mark_parts(prompt.content, part.id)
323
+
324
+
325
+ def _mark_response(tracker: Tracker | None, prompt: P.Prompt, parts: Sequence[object]) -> None:
326
+ """Mark ``prompt``'s messages as sent with the response's id (its first
327
+ metadata part's)."""
328
+ metadata = next((p for p in parts if isinstance(p, R.ResponseMetadataPart)), None)
329
+ if tracker is not None and metadata is not None and metadata.id is not None:
330
+ tracker.mark_parts(prompt.content, metadata.id)
331
+
332
+
333
+ def _prepared(tracker: Tracker | None, options: ProviderOptions) -> ProviderOptions:
334
+ if tracker is None:
335
+ return options
336
+ prepared = tracker.prepare_unsafe(options.prompt)
337
+ if prepared is None:
338
+ return options
339
+ return replace(
340
+ options,
341
+ previous_response_id=prepared.previous_response_id,
342
+ incremental_prompt=prepared.prompt,
343
+ )
344
+
345
+
346
+ def _fallback(options: ProviderOptions) -> ProviderOptions:
347
+ return replace(
348
+ options, incremental_prompt=None, previous_response_id=None, incremental_fallback=True
349
+ )
350
+
351
+
352
+ @dataclass(frozen=True)
353
+ class Service:
354
+ """A language model (made by ``make``)."""
355
+
356
+ _generate: GenerateFn
357
+ _stream: StreamFn
358
+ codec_transformer: CodecTransformer = default_codec_transformer
359
+ supports_system_messages_in_history: Effect[bool] | None = None
360
+ id_generator: IdService = default_id_generator
361
+ _decoders: dict[tuple[bool, bool, bool], tuple[tuple[AnyTool, ...], Any]] = field(
362
+ default_factory=dict[tuple[bool, bool, bool], tuple[tuple[AnyTool, ...], Any]]
363
+ )
364
+
365
+ def _decoder(
366
+ self,
367
+ kit: K.WithHandler[Any, Any, Any, Any] | None,
368
+ encoded: bool,
369
+ stream: bool,
370
+ deferred: bool = False,
371
+ ) -> Callable[[Sequence[EncodedPart]], Effect[list[Any], SchemaError | AiError]]:
372
+ """Decodes a response's parts; ``deferred`` also takes calls to
373
+ tools outside ``kit``, which otherwise fail with
374
+ ``ToolNotFoundError`` before the parts are decoded."""
375
+ tools = () if kit is None else tuple(kit.tools.values())
376
+ key = (encoded, stream, deferred)
377
+ cached = self._decoders.get(key)
378
+ if (
379
+ cached is not None
380
+ and len(cached[0]) == len(tools)
381
+ and all(a is b for a, b in zip(cached[0], tools, strict=True))
382
+ ):
383
+ return cached[1]
384
+ toolkit = K.empty if kit is None else _decoded_toolkit(kit, encoded)
385
+ part = R.stream_part(toolkit) if stream else R.part(toolkit)
386
+ if deferred:
387
+ part = S.Union(part, _UNDECLARED_TOOL_CALL)
388
+ decoder = cast(
389
+ "Callable[[Sequence[EncodedPart]], Effect[list[Any], SchemaError]]",
390
+ S.decode_unknown_effect(S.Array(part)),
391
+ )
392
+ self._decoders[key] = (tools, decoder)
393
+ return decoder
394
+
395
+ def _request(self, options: ProviderOptions) -> Effect[Sequence[EncodedPart], AiError, Any]:
396
+ def admitted(parts: Sequence[EncodedPart]) -> Effect[Sequence[EncodedPart], AiError]:
397
+ error = Ids.Ledger(options.prompt.content).admit(parts, "generateText")
398
+ return fx.succeed(parts) if error is None else fx.fail(error)
399
+
400
+ return self._provider_request(options).flat_map(admitted)
401
+
402
+ def _provider_request(
403
+ self, options: ProviderOptions
404
+ ) -> Effect[Sequence[EncodedPart], AiError, Any]:
405
+ first = self._generate(options)
406
+ if options.incremental_prompt is None:
407
+ return first
408
+ return first.catch_all(
409
+ lambda error: (
410
+ self._generate(_fallback(options))
411
+ if isinstance(error.reason, InvalidRequestError)
412
+ else fx.fail(error)
413
+ )
414
+ )
415
+
416
+ def _request_stream(self, options: ProviderOptions) -> Stream[EncodedPart, AiError, Any]:
417
+ def checked() -> Stream[EncodedPart, AiError, Any]:
418
+ ledger = Ids.Ledger(options.prompt.content)
419
+
420
+ def admit(chunk: tuple[EncodedPart, ...]) -> Effect[tuple[EncodedPart, ...], AiError]:
421
+ error = ledger.admit(chunk, "streamText")
422
+ return fx.succeed(chunk) if error is None else fx.fail(error)
423
+
424
+ return self._provider_stream(options).map_array_effect(admit)
425
+
426
+ return StreamC.suspend(checked)
427
+
428
+ def _provider_stream(self, options: ProviderOptions) -> Stream[EncodedPart, AiError, Any]:
429
+ first = self._stream(options)
430
+ if options.incremental_prompt is None:
431
+ return first
432
+ # Only parts with content count as emitted: a lone response-metadata
433
+ # part still allows the full-prompt retry.
434
+ emitted = False
435
+
436
+ def seen(part: EncodedPart) -> Effect[None]:
437
+ def run() -> None:
438
+ nonlocal emitted
439
+ if part.get("type") != "response-metadata":
440
+ emitted = True
441
+
442
+ return fx.sync(run)
443
+
444
+ return first.tap(seen).catch_all(
445
+ lambda error: (
446
+ self._stream(_fallback(options))
447
+ if isinstance(error.reason, InvalidRequestError) and not emitted
448
+ else StreamC.fail(error)
449
+ )
450
+ )
451
+
452
+ def _content(
453
+ self,
454
+ options: ProviderOptions,
455
+ toolkit: Any,
456
+ tool_choice: ToolChoice,
457
+ concurrency: Concurrency,
458
+ disable_tool_call_resolution: bool,
459
+ ) -> Effect[list[Any], Any, Any]:
460
+ def with_tracker(found: Any) -> Effect[list[Any], Any, Any]:
461
+ tracker = cast("Tracker | None", found.value if found is not None else None)
462
+ if toolkit is None:
463
+ return run(None, tracker)
464
+ kit_effect = _as_kit_effect(toolkit)
465
+ return kit_effect.flat_map(lambda kit: run(kit, tracker))
466
+
467
+ deferred = options.tool_call_validation == "deferred"
468
+
469
+ def run(kit: K.WithHandler[Any, Any, Any, Any] | None, tracker: Tracker | None) -> Any:
470
+ approvals = A.collect(options.prompt.content)
471
+ error = A.pending_check(approvals, kit, "generateText")
472
+ if error is not None:
473
+ return fx.fail(error)
474
+ if kit is None or not kit.tools:
475
+ request = _prepared(tracker, options)
476
+ decode = self._decoder(None, False, False, deferred)
477
+ return (
478
+ self._request(request)
479
+ .flat_map(decode)
480
+ .tap(
481
+ lambda content: fx.sync(
482
+ lambda: _mark_response(tracker, request.prompt, content)
483
+ )
484
+ )
485
+ )
486
+ return A.pre_resolve(approvals, kit, concurrency).flat_map(
487
+ lambda pre: run_tools(kit, tracker, approvals, pre)
488
+ )
489
+
490
+ def run_tools(
491
+ kit: K.WithHandler[Any, Any, Any, Any],
492
+ tracker: Tracker | None,
493
+ approvals: A.Approvals,
494
+ pre: list[R.AnyToolResultPart],
495
+ ) -> Effect[list[Any], Any, Any]:
496
+ prompt = A.strip_resolved(A.with_results(options.prompt, pre), approvals)
497
+ with_prompt = replace(options, prompt=prompt)
498
+ request = _prepared(tracker, _with_tools(with_prompt, kit, tool_choice))
499
+ decode = self._decoder(
500
+ kit, disable_tool_call_resolution and not deferred, False, deferred
501
+ )
502
+
503
+ def resolve(raw: Sequence[EncodedPart]) -> Effect[list[Any], Any, Any]:
504
+ def results(content: list[Any]) -> Effect[list[Any], Any, Any]:
505
+ if disable_tool_call_resolution:
506
+ return fx.succeed([*pre, *content])
507
+ calls = [c for c in _tool_calls(raw) if c.get("name") in kit.tools]
508
+ incomplete = _incomplete_reason(raw)
509
+ if incomplete is not None:
510
+ interrupted = [
511
+ interrupted_result(
512
+ cast("str", c["id"]), cast("str", c["name"]), incomplete
513
+ )
514
+ for c in calls
515
+ ]
516
+ return fx.succeed([*pre, *content, *interrupted])
517
+ resolved = _resolve(kit, calls, request.prompt.content, concurrency).filter(
518
+ lambda result: (
519
+ isinstance(result, R.ToolApprovalRequestPart) or not result.preliminary
520
+ )
521
+ )
522
+ return resolved.run_collect().map(lambda rs: [*pre, *content, *rs])
523
+
524
+ def after(content: list[Any]) -> Effect[list[Any], Any, Any]:
525
+ # The tracker learns the response only once its tool
526
+ # calls are resolved, as in Effect.
527
+ return results(content).tap(
528
+ lambda _: fx.sync(lambda: _mark_response(tracker, request.prompt, content))
529
+ )
530
+
531
+ validate = (
532
+ _validate_provider_executed(kit, raw, encoded=True)
533
+ if deferred
534
+ else fx.void
535
+ if disable_tool_call_resolution
536
+ else _validate_provider_executed(kit, raw)
537
+ )
538
+ return decode(raw).flat_map(lambda content: validate.and_then(after(content)))
539
+
540
+ return self._request(request).flat_map(resolve)
541
+
542
+ def annotated(span: Span | None) -> Effect[list[Any], Any, Any]:
543
+ if span is not None:
544
+ output = options.response_format.type
545
+ _annotate(span, output, tool_choice, concurrency)
546
+ return fx.service_option(ResponseIdTracker).flat_map(with_tracker)
547
+
548
+ return fx.suspend(lambda: annotated(options.span))
549
+
550
+ def generate_text(
551
+ self,
552
+ prompt: P.RawInput,
553
+ *,
554
+ toolkit: Any = None,
555
+ tool_choice: ToolChoice = "auto",
556
+ concurrency: Concurrency = "unbounded",
557
+ disable_tool_call_resolution: bool = False,
558
+ tool_call_validation: ToolCallValidation = "strict",
559
+ ) -> Effect[GenerateTextResponse[Any, Any], Any, Any]:
560
+ """See the module's ``generate_text``."""
561
+ return self._spanned(
562
+ "LanguageModel.generateText",
563
+ "generateText",
564
+ lambda span: self._content(
565
+ ProviderOptions(
566
+ P.make(prompt),
567
+ span=span,
568
+ tool_call_validation=_validation(
569
+ disable_tool_call_resolution, tool_call_validation
570
+ ),
571
+ ),
572
+ toolkit,
573
+ tool_choice,
574
+ concurrency,
575
+ disable_tool_call_resolution,
576
+ ).map(GenerateTextResponse[Any, Any]),
577
+ {},
578
+ )
579
+
580
+ def generate_object(
581
+ self,
582
+ prompt: P.RawInput,
583
+ *,
584
+ schema: S.Top,
585
+ object_name: str | None = None,
586
+ toolkit: Any = None,
587
+ tool_choice: ToolChoice = "auto",
588
+ concurrency: Concurrency = "unbounded",
589
+ disable_tool_call_resolution: bool = False,
590
+ tool_call_validation: ToolCallValidation = "strict",
591
+ ) -> Effect[GenerateObjectResponse[Any, Any, Any], Any, Any]:
592
+ """See the module's ``generate_object``."""
593
+ name = get_object_name(object_name, schema)
594
+
595
+ def body(span: Span) -> Effect[GenerateObjectResponse[Any, Any, Any], Any, Any]:
596
+ options = ProviderOptions(
597
+ P.make(prompt),
598
+ response_format=JsonFormat(name, schema),
599
+ span=span,
600
+ tool_call_validation=_validation(
601
+ disable_tool_call_resolution, tool_call_validation
602
+ ),
603
+ )
604
+ content = self._content(
605
+ options, toolkit, tool_choice, concurrency, disable_tool_call_resolution
606
+ )
607
+ return content.flat_map(
608
+ lambda parts: self._structured(parts, schema).map(
609
+ lambda value: GenerateObjectResponse[Any, Any, Any](parts, value)
610
+ )
611
+ )
612
+
613
+ return self._spanned(
614
+ "LanguageModel.generateObject",
615
+ "generateObject",
616
+ body,
617
+ {"effect.ai.object_name": name},
618
+ )
619
+
620
+ def _structured(self, parts: Sequence[object], schema: S.Top) -> Effect[object, AiError]:
621
+ text = "".join(part.text for part in parts if isinstance(part, R.TextPart))
622
+ if not text:
623
+ reason = StructuredOutputError(
624
+ description="No text content in response", response_text=text
625
+ )
626
+ return fx.fail(_error("generateObject", reason))
627
+ try:
628
+ codec = self.codec_transformer(schema)[0]
629
+ except Exception as error:
630
+ reason = UnsupportedSchemaError(description=str(error))
631
+ return fx.fail(_error("generateObject", reason))
632
+ decode = cast("Any", S.decode_unknown_effect(S.from_json_string(codec)))
633
+ return cast("Effect[object, SchemaError]", decode(text)).map_error(
634
+ lambda error: _error(
635
+ "generateObject", StructuredOutputError.from_schema_error(error, text)
636
+ )
637
+ )
638
+
639
+ def _spanned(
640
+ self,
641
+ name: str,
642
+ method: str,
643
+ body: Callable[[Span], Effect[Any, Any, Any]],
644
+ attributes: dict[str, object],
645
+ ) -> Effect[Any, Any, Any]:
646
+ from pyfect.tracer._spans import use_span
647
+
648
+ def run(span: Span) -> Effect[Any, Any, Any]:
649
+ for key, value in attributes.items():
650
+ span.attribute(key, value)
651
+ return body(span).catch_all(
652
+ lambda error: (
653
+ fx.fail(_error(method, InvalidOutputError.from_schema_error(error)))
654
+ if isinstance(error, SchemaError)
655
+ else fx.fail(error)
656
+ )
657
+ )
658
+
659
+ provided = use_span(name, run, kind="client")
660
+ return provided.pipe(fx.provide_service(IdGenerator, self.id_generator))
661
+
662
+ def stream_text(
663
+ self,
664
+ prompt: P.RawInput,
665
+ *,
666
+ toolkit: Any = None,
667
+ tool_choice: ToolChoice = "auto",
668
+ concurrency: Concurrency = "unbounded",
669
+ disable_tool_call_resolution: bool = False,
670
+ tool_call_validation: ToolCallValidation = "strict",
671
+ ) -> Stream[Any, Any, Any]:
672
+ """See the module's ``stream_text``."""
673
+ from pyfect.stream import provide_service
674
+ from pyfect.tracer._spans import make_span_scoped
675
+
676
+ def with_span(span: Span) -> Effect[Stream[Any, Any, Any], Any, Any]:
677
+ options = ProviderOptions(
678
+ P.make(prompt),
679
+ span=span,
680
+ tool_call_validation=_validation(
681
+ disable_tool_call_resolution, tool_call_validation
682
+ ),
683
+ )
684
+ _annotate(span, "text", tool_choice, concurrency)
685
+ return fx.service_option(ResponseIdTracker).flat_map(
686
+ lambda found: with_tracker(options, found.value if found is not None else None)
687
+ )
688
+
689
+ def with_tracker(
690
+ options: ProviderOptions, tracker: Tracker | None
691
+ ) -> Effect[Stream[Any, Any, Any], Any, Any]:
692
+ if toolkit is None:
693
+ error = A.pending_check(A.collect(options.prompt.content), None, "streamText")
694
+ if error is not None:
695
+ return fx.fail(error)
696
+ request = _prepared(tracker, options)
697
+ deferred = options.tool_call_validation == "deferred"
698
+ return fx.succeed(self._stream_parts(request, None, tracker, False, deferred))
699
+ return _as_kit_effect(toolkit).flat_map(
700
+ lambda kit: self._stream_with(
701
+ kit,
702
+ options,
703
+ tracker,
704
+ tool_choice=tool_choice,
705
+ concurrency=concurrency,
706
+ disable_tool_call_resolution=disable_tool_call_resolution,
707
+ )
708
+ )
709
+
710
+ span = make_span_scoped("LanguageModel.streamText", kind="client")
711
+ stream = StreamC.unwrap(span.flat_map(with_span))
712
+ return stream.catch_all(
713
+ lambda error: StreamC.fail(
714
+ _error("streamText", InvalidOutputError.from_schema_error(error))
715
+ if isinstance(error, SchemaError)
716
+ else error
717
+ )
718
+ ).pipe(provide_service(IdGenerator, self.id_generator))
719
+
720
+ def _stream_parts(
721
+ self,
722
+ request: ProviderOptions,
723
+ kit: K.WithHandler[Any, Any, Any, Any] | None,
724
+ tracker: Tracker | None,
725
+ encoded: bool,
726
+ deferred: bool = False,
727
+ ) -> Stream[Any, Any, Any]:
728
+ """The provider's parts, decoded; ``request`` is already prepared
729
+ by the tracker. ``deferred`` also checks provider-executed calls
730
+ against ``kit``'s encoded parameters."""
731
+ decode = self._decoder(kit, encoded, True, deferred)
732
+
733
+ def decode_chunk(chunk: Sequence[EncodedPart]) -> Effect[tuple[Any, ...], Any, Any]:
734
+ def marked(parts: list[Any]) -> tuple[Any, ...]:
735
+ _mark(tracker, request.prompt, parts)
736
+ return tuple(parts)
737
+
738
+ decoded = decode(chunk).map(marked)
739
+ if deferred and kit is not None:
740
+ return _validate_provider_executed(kit, chunk, encoded=True).and_then(decoded)
741
+ return decoded
742
+
743
+ return self._request_stream(request).map_array_effect(decode_chunk)
744
+
745
+ def _stream_with(
746
+ self,
747
+ kit: K.WithHandler[Any, Any, Any, Any],
748
+ options: ProviderOptions,
749
+ tracker: Tracker | None,
750
+ *,
751
+ tool_choice: ToolChoice,
752
+ concurrency: Concurrency,
753
+ disable_tool_call_resolution: bool,
754
+ ) -> Effect[Stream[Any, Any, Any], Any, Any]:
755
+ approvals = A.collect(options.prompt.content)
756
+ error = A.pending_check(approvals, kit, "streamText")
757
+ if error is not None:
758
+ return fx.fail(error)
759
+ deferred = options.tool_call_validation == "deferred"
760
+ if not kit.tools:
761
+ request = _prepared(tracker, options)
762
+ return fx.succeed(self._stream_parts(request, None, tracker, False, deferred))
763
+
764
+ def with_pre(pre: list[R.AnyToolResultPart]) -> Effect[Stream[Any, Any, Any], Any, Any]:
765
+ prompt = A.strip_resolved(A.with_results(options.prompt, pre), approvals)
766
+ request = _prepared(
767
+ tracker, _with_tools(replace(options, prompt=prompt), kit, tool_choice)
768
+ )
769
+ if disable_tool_call_resolution:
770
+ return fx.succeed(self._stream_parts(request, kit, tracker, not deferred, deferred))
771
+ decode = self._decoder(kit, False, True)
772
+ # Pre-resolved results are emitted so a chat keeps them in its
773
+ # history, their encoded form as the result.
774
+ emitted = [replace(result, result=result.encoded_result) for result in pre]
775
+
776
+ def on_chunk(chunk: Sequence[EncodedPart]) -> Effect[list[Any], Any, Any]:
777
+ def checked(parts: list[Any]) -> Effect[list[Any], Any, Any]:
778
+ _mark(tracker, request.prompt, parts)
779
+ return fx.succeed(parts)
780
+
781
+ return decode(chunk).flat_map(
782
+ lambda parts: _validate_provider_executed(kit, chunk).and_then(
783
+ fx.suspend(lambda: checked(parts))
784
+ )
785
+ )
786
+
787
+ return resolve_stream(
788
+ kit,
789
+ self._request_stream(request),
790
+ on_chunk,
791
+ concurrency,
792
+ messages=request.prompt.content,
793
+ emitted=emitted,
794
+ )
795
+
796
+ return A.pre_resolve(approvals, kit, concurrency).flat_map(with_pre)
797
+
798
+
799
+ def _with_tools(
800
+ options: ProviderOptions, kit: K.WithHandler[Any, Any, Any, Any], tool_choice: ToolChoice
801
+ ) -> ProviderOptions:
802
+ """``options`` offering ``kit``'s tools (those ``one_of`` names)."""
803
+ tools = tuple(kit.tools.values())
804
+ if isinstance(tool_choice, dict) and "one_of" in tool_choice:
805
+ one_of = tool_choice.get("one_of", ())
806
+ tools = tuple(tool for tool in tools if tool.name in one_of)
807
+ return replace(options, tools=tools, tool_choice=tool_choice)
808
+
809
+
810
+ def _as_kit_effect(toolkit: object) -> Effect[K.WithHandler[Any, Any, Any, Any], Any, Any]:
811
+ if isinstance(toolkit, Effect):
812
+ return cast("Effect[K.WithHandler[Any, Any, Any, Any], Any, Any]", toolkit)
813
+ return fx.succeed(cast("K.WithHandler[Any, Any, Any, Any]", toolkit))
814
+
815
+
816
+ class LanguageModel(Tag[Service], key="effect/ai/LanguageModel"):
817
+ """The current language model."""
818
+
819
+
820
+ def make(
821
+ *,
822
+ generate_text: GenerateFn,
823
+ stream_text: StreamFn,
824
+ codec_transformer: CodecTransformer | None = None,
825
+ supports_system_messages_in_history: Effect[bool] | None = None,
826
+ ) -> Effect[Service]:
827
+ """A language model from a provider's two functions. Its requests use
828
+ the ``IdGenerator`` in context here (else the default one)."""
829
+ if supports_system_messages_in_history is not None:
830
+ require_effect(supports_system_messages_in_history, "supports_system_messages_in_history")
831
+ return fx.service_option(IdGenerator).map(
832
+ lambda found: Service(
833
+ generate_text,
834
+ stream_text,
835
+ codec_transformer or default_codec_transformer,
836
+ supports_system_messages_in_history,
837
+ found.value if found is not None else default_id_generator,
838
+ )
839
+ )
840
+
841
+
842
+ # Module functions ----------------------------------------------------------------------
843
+
844
+ type _ToolkitInput[NN: LiteralString, RP, EE, RR] = (
845
+ K.WithHandler[NN, RP, EE, RR] | Effect[K.WithHandler[NN, RP, EE, RR], EE, RR]
846
+ )
847
+
848
+
849
+ @overload
850
+ def generate_text(
851
+ prompt: P.RawInput,
852
+ *,
853
+ toolkit: None = None,
854
+ tool_choice: ToolChoice = "auto",
855
+ concurrency: Concurrency = "unbounded",
856
+ disable_tool_call_resolution: Literal[True],
857
+ tool_call_validation: Literal["deferred"],
858
+ ) -> Effect[GenerateTextResponse[str, Never], AiError, LanguageModel]: ...
859
+ @overload
860
+ def generate_text(
861
+ prompt: P.RawInput,
862
+ *,
863
+ toolkit: None = None,
864
+ tool_choice: ToolChoice = "auto",
865
+ concurrency: Concurrency = "unbounded",
866
+ disable_tool_call_resolution: bool = False,
867
+ tool_call_validation: Literal["strict"] = "strict",
868
+ ) -> Effect[GenerateTextResponse[Never, Never], AiError, LanguageModel]: ...
869
+ @overload
870
+ def generate_text[NN: LiteralString, RP, EE, RR](
871
+ prompt: P.RawInput,
872
+ *,
873
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
874
+ tool_choice: ToolChoice = "auto",
875
+ concurrency: Concurrency = "unbounded",
876
+ disable_tool_call_resolution: Literal[True],
877
+ tool_call_validation: Literal["deferred"],
878
+ ) -> Effect[GenerateTextResponse[str, RP], AiError | EE, LanguageModel | RR]: ...
879
+ @overload
880
+ def generate_text[NN: LiteralString, RP, EE, RR](
881
+ prompt: P.RawInput,
882
+ *,
883
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
884
+ tool_choice: ToolChoice = "auto",
885
+ concurrency: Concurrency = "unbounded",
886
+ disable_tool_call_resolution: bool = False,
887
+ tool_call_validation: Literal["strict"] = "strict",
888
+ ) -> Effect[GenerateTextResponse[NN, RP], AiError | EE, LanguageModel | RR]: ...
889
+ def generate_text(
890
+ prompt: P.RawInput,
891
+ *,
892
+ toolkit: Any = None,
893
+ tool_choice: ToolChoice = "auto",
894
+ concurrency: Concurrency = "unbounded",
895
+ disable_tool_call_resolution: bool = False,
896
+ tool_call_validation: ToolCallValidation = "strict",
897
+ ) -> Effect[GenerateTextResponse[Any, Any], Any, Any]:
898
+ """Generate a response to ``prompt``. With a ``toolkit`` (its handlers
899
+ or the toolkit itself), the model may call its tools: their results
900
+ follow the model's parts, unless ``disable_tool_call_resolution``.
901
+ ``concurrency`` bounds the tool calls running at once."""
902
+ return LanguageModel().flat_map(
903
+ lambda model: model.generate_text(
904
+ prompt,
905
+ toolkit=toolkit,
906
+ tool_choice=tool_choice,
907
+ concurrency=concurrency,
908
+ disable_tool_call_resolution=disable_tool_call_resolution,
909
+ tool_call_validation=tool_call_validation,
910
+ )
911
+ )
912
+
913
+
914
+ @overload
915
+ def generate_object[A](
916
+ prompt: P.RawInput,
917
+ *,
918
+ schema: S.Codec[A, Any, Any, Any],
919
+ object_name: str | None = None,
920
+ toolkit: None = None,
921
+ tool_choice: ToolChoice = "auto",
922
+ concurrency: Concurrency = "unbounded",
923
+ disable_tool_call_resolution: Literal[True],
924
+ tool_call_validation: Literal["deferred"],
925
+ ) -> Effect[GenerateObjectResponse[str, Never, A], AiError, LanguageModel]: ...
926
+ @overload
927
+ def generate_object[A](
928
+ prompt: P.RawInput,
929
+ *,
930
+ schema: S.Codec[A, Any, Any, Any],
931
+ object_name: str | None = None,
932
+ toolkit: None = None,
933
+ tool_choice: ToolChoice = "auto",
934
+ concurrency: Concurrency = "unbounded",
935
+ disable_tool_call_resolution: bool = False,
936
+ tool_call_validation: Literal["strict"] = "strict",
937
+ ) -> Effect[GenerateObjectResponse[Never, Never, A], AiError, LanguageModel]: ...
938
+ @overload
939
+ def generate_object[A, NN: LiteralString, RP, EE, RR](
940
+ prompt: P.RawInput,
941
+ *,
942
+ schema: S.Codec[A, Any, Any, Any],
943
+ object_name: str | None = None,
944
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
945
+ tool_choice: ToolChoice = "auto",
946
+ concurrency: Concurrency = "unbounded",
947
+ disable_tool_call_resolution: Literal[True],
948
+ tool_call_validation: Literal["deferred"],
949
+ ) -> Effect[GenerateObjectResponse[str, RP, A], AiError | EE, LanguageModel | RR]: ...
950
+ @overload
951
+ def generate_object[A, NN: LiteralString, RP, EE, RR](
952
+ prompt: P.RawInput,
953
+ *,
954
+ schema: S.Codec[A, Any, Any, Any],
955
+ object_name: str | None = None,
956
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
957
+ tool_choice: ToolChoice = "auto",
958
+ concurrency: Concurrency = "unbounded",
959
+ disable_tool_call_resolution: bool = False,
960
+ tool_call_validation: Literal["strict"] = "strict",
961
+ ) -> Effect[GenerateObjectResponse[NN, RP, A], AiError | EE, LanguageModel | RR]: ...
962
+ def generate_object(
963
+ prompt: P.RawInput,
964
+ *,
965
+ schema: S.Top,
966
+ object_name: str | None = None,
967
+ toolkit: Any = None,
968
+ tool_choice: ToolChoice = "auto",
969
+ concurrency: Concurrency = "unbounded",
970
+ disable_tool_call_resolution: bool = False,
971
+ tool_call_validation: ToolCallValidation = "strict",
972
+ ) -> Effect[GenerateObjectResponse[Any, Any, Any], Any, Any]:
973
+ """Generate a JSON object matching ``schema`` (named ``object_name``,
974
+ else the schema's identifier) and decode it into ``value``."""
975
+ return LanguageModel().flat_map(
976
+ lambda model: model.generate_object(
977
+ prompt,
978
+ schema=schema,
979
+ object_name=object_name,
980
+ toolkit=toolkit,
981
+ tool_choice=tool_choice,
982
+ concurrency=concurrency,
983
+ disable_tool_call_resolution=disable_tool_call_resolution,
984
+ tool_call_validation=tool_call_validation,
985
+ )
986
+ )
987
+
988
+
989
+ @overload
990
+ def stream_text(
991
+ prompt: P.RawInput,
992
+ *,
993
+ toolkit: None = None,
994
+ tool_choice: ToolChoice = "auto",
995
+ concurrency: Concurrency = "unbounded",
996
+ disable_tool_call_resolution: Literal[True],
997
+ tool_call_validation: Literal["deferred"],
998
+ ) -> Stream[R.StreamPart[str, Never], AiError, LanguageModel]: ...
999
+ @overload
1000
+ def stream_text(
1001
+ prompt: P.RawInput,
1002
+ *,
1003
+ toolkit: None = None,
1004
+ tool_choice: ToolChoice = "auto",
1005
+ concurrency: Concurrency = "unbounded",
1006
+ disable_tool_call_resolution: bool = False,
1007
+ tool_call_validation: Literal["strict"] = "strict",
1008
+ ) -> Stream[R.StreamPart[Never, Never], AiError, LanguageModel]: ...
1009
+ @overload
1010
+ def stream_text[NN: LiteralString, RP, EE, RR](
1011
+ prompt: P.RawInput,
1012
+ *,
1013
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
1014
+ tool_choice: ToolChoice = "auto",
1015
+ concurrency: Concurrency = "unbounded",
1016
+ disable_tool_call_resolution: Literal[True],
1017
+ tool_call_validation: Literal["deferred"],
1018
+ ) -> Stream[R.StreamPart[str, RP], AiError | EE, LanguageModel | RR]: ...
1019
+ @overload
1020
+ def stream_text[NN: LiteralString, RP, EE, RR](
1021
+ prompt: P.RawInput,
1022
+ *,
1023
+ toolkit: _ToolkitInput[NN, RP, EE, RR],
1024
+ tool_choice: ToolChoice = "auto",
1025
+ concurrency: Concurrency = "unbounded",
1026
+ disable_tool_call_resolution: bool = False,
1027
+ tool_call_validation: Literal["strict"] = "strict",
1028
+ ) -> Stream[R.StreamPart[NN, RP], AiError | EE, LanguageModel | RR]: ...
1029
+ def stream_text(
1030
+ prompt: P.RawInput,
1031
+ *,
1032
+ toolkit: Any = None,
1033
+ tool_choice: ToolChoice = "auto",
1034
+ concurrency: Concurrency = "unbounded",
1035
+ disable_tool_call_resolution: bool = False,
1036
+ tool_call_validation: ToolCallValidation = "strict",
1037
+ ) -> Stream[Any, Any, Any]:
1038
+ """Stream a response to ``prompt``: the model's parts as they come,
1039
+ then its tool calls' results (preliminary ones included), then the
1040
+ finish part."""
1041
+ return StreamC.unwrap(
1042
+ LanguageModel().map(
1043
+ lambda model: model.stream_text(
1044
+ prompt,
1045
+ toolkit=toolkit,
1046
+ tool_choice=tool_choice,
1047
+ concurrency=concurrency,
1048
+ disable_tool_call_resolution=disable_tool_call_resolution,
1049
+ tool_call_validation=tool_call_validation,
1050
+ )
1051
+ )
1052
+ )
1053
+
1054
+
1055
+ __all__ = [
1056
+ "AiError",
1057
+ "EncodedPart",
1058
+ "GenerateFn",
1059
+ "GenerateObjectResponse",
1060
+ "GenerateTextResponse",
1061
+ "JsonFormat",
1062
+ "LanguageModel",
1063
+ "ProviderOptions",
1064
+ "Service",
1065
+ "StreamFn",
1066
+ "TextFormat",
1067
+ "ToolCallValidation",
1068
+ "ToolChoice",
1069
+ "ToolChoiceOneOf",
1070
+ "ToolChoiceTool",
1071
+ "default_codec_transformer",
1072
+ "generate_object",
1073
+ "generate_text",
1074
+ "get_object_name",
1075
+ "make",
1076
+ "stream_text",
1077
+ ]