pydantic-ai-slim 0.2.10__tar.gz → 0.2.12__tar.gz

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.

Potentially problematic release.


This version of pydantic-ai-slim might be problematic. Click here for more details.

Files changed (74) hide show
  1. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/PKG-INFO +5 -5
  2. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_agent_graph.py +29 -35
  3. pydantic_ai_slim-0.2.10/pydantic_ai/_pydantic.py → pydantic_ai_slim-0.2.12/pydantic_ai/_function_schema.py +48 -8
  4. pydantic_ai_slim-0.2.12/pydantic_ai/_output.py +439 -0
  5. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/agent.py +15 -15
  6. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/mcp.py +1 -1
  7. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/messages.py +2 -2
  8. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/__init__.py +39 -3
  9. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/anthropic.py +6 -1
  10. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/bedrock.py +43 -16
  11. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/cohere.py +4 -0
  12. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/gemini.py +68 -108
  13. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/google.py +45 -110
  14. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/groq.py +17 -2
  15. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/mistral.py +4 -0
  16. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/openai.py +22 -157
  17. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/__init__.py +39 -0
  18. {pydantic_ai_slim-0.2.10/pydantic_ai/models → pydantic_ai_slim-0.2.12/pydantic_ai/profiles}/_json_schema.py +23 -2
  19. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/amazon.py +9 -0
  20. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/anthropic.py +8 -0
  21. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/cohere.py +8 -0
  22. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/deepseek.py +8 -0
  23. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/google.py +100 -0
  24. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/grok.py +8 -0
  25. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/meta.py +9 -0
  26. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/mistral.py +8 -0
  27. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/openai.py +144 -0
  28. pydantic_ai_slim-0.2.12/pydantic_ai/profiles/qwen.py +9 -0
  29. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/__init__.py +18 -0
  30. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/anthropic.py +5 -0
  31. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/azure.py +34 -0
  32. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/bedrock.py +60 -1
  33. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/cohere.py +5 -0
  34. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/deepseek.py +12 -0
  35. pydantic_ai_slim-0.2.12/pydantic_ai/providers/fireworks.py +99 -0
  36. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/google.py +5 -0
  37. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/google_gla.py +5 -0
  38. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/google_vertex.py +5 -0
  39. pydantic_ai_slim-0.2.10/pydantic_ai/providers/openrouter.py → pydantic_ai_slim-0.2.12/pydantic_ai/providers/grok.py +22 -9
  40. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/groq.py +25 -0
  41. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/mistral.py +5 -0
  42. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/providers/openai.py +5 -0
  43. pydantic_ai_slim-0.2.12/pydantic_ai/providers/openrouter.py +105 -0
  44. pydantic_ai_slim-0.2.12/pydantic_ai/providers/together.py +96 -0
  45. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/result.py +34 -103
  46. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/tools.py +28 -58
  47. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pyproject.toml +1 -1
  48. pydantic_ai_slim-0.2.10/pydantic_ai/_output.py +0 -292
  49. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/.gitignore +0 -0
  50. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/LICENSE +0 -0
  51. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/README.md +0 -0
  52. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/__init__.py +0 -0
  53. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/__main__.py +0 -0
  54. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_a2a.py +0 -0
  55. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_cli.py +0 -0
  56. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_griffe.py +0 -0
  57. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_parts_manager.py +0 -0
  58. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_system_prompt.py +0 -0
  59. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/_utils.py +0 -0
  60. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/common_tools/__init__.py +0 -0
  61. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  62. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/common_tools/tavily.py +0 -0
  63. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/direct.py +0 -0
  64. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/exceptions.py +0 -0
  65. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/format_as_xml.py +0 -0
  66. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/format_prompt.py +0 -0
  67. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/fallback.py +0 -0
  68. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/function.py +0 -0
  69. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/instrumented.py +0 -0
  70. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/test.py +0 -0
  71. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/models/wrapper.py +0 -0
  72. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/py.typed +0 -0
  73. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/settings.py +0 -0
  74. {pydantic_ai_slim-0.2.10 → pydantic_ai_slim-0.2.12}/pydantic_ai/usage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 0.2.10
3
+ Version: 0.2.12
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Author-email: Samuel Colvin <samuel@pydantic.dev>, Marcelo Trylesinski <marcelotryle@gmail.com>, David Montague <david@pydantic.dev>, Alex Hall <alex@pydantic.dev>
6
6
  License-Expression: MIT
@@ -30,11 +30,11 @@ Requires-Dist: exceptiongroup; python_version < '3.11'
30
30
  Requires-Dist: griffe>=1.3.2
31
31
  Requires-Dist: httpx>=0.27
32
32
  Requires-Dist: opentelemetry-api>=1.28.0
33
- Requires-Dist: pydantic-graph==0.2.10
33
+ Requires-Dist: pydantic-graph==0.2.12
34
34
  Requires-Dist: pydantic>=2.10
35
35
  Requires-Dist: typing-inspection>=0.4.0
36
36
  Provides-Extra: a2a
37
- Requires-Dist: fasta2a==0.2.10; extra == 'a2a'
37
+ Requires-Dist: fasta2a==0.2.12; extra == 'a2a'
38
38
  Provides-Extra: anthropic
39
39
  Requires-Dist: anthropic>=0.52.0; extra == 'anthropic'
40
40
  Provides-Extra: bedrock
@@ -48,7 +48,7 @@ Requires-Dist: cohere>=5.13.11; (platform_system != 'Emscripten') and extra == '
48
48
  Provides-Extra: duckduckgo
49
49
  Requires-Dist: duckduckgo-search>=7.0.0; extra == 'duckduckgo'
50
50
  Provides-Extra: evals
51
- Requires-Dist: pydantic-evals==0.2.10; extra == 'evals'
51
+ Requires-Dist: pydantic-evals==0.2.12; extra == 'evals'
52
52
  Provides-Extra: google
53
53
  Requires-Dist: google-genai>=1.15.0; extra == 'google'
54
54
  Provides-Extra: groq
@@ -56,7 +56,7 @@ Requires-Dist: groq>=0.15.0; extra == 'groq'
56
56
  Provides-Extra: logfire
57
57
  Requires-Dist: logfire>=3.11.0; extra == 'logfire'
58
58
  Provides-Extra: mcp
59
- Requires-Dist: mcp>=1.8.0; (python_version >= '3.10') and extra == 'mcp'
59
+ Requires-Dist: mcp>=1.9.0; (python_version >= '3.10') and extra == 'mcp'
60
60
  Provides-Extra: mistral
61
61
  Requires-Dist: mistralai>=1.2.5; extra == 'mistral'
62
62
  Provides-Extra: openai
@@ -24,7 +24,7 @@ from . import (
24
24
  result,
25
25
  usage as _usage,
26
26
  )
27
- from .result import OutputDataT, ToolOutput
27
+ from .result import OutputDataT
28
28
  from .settings import ModelSettings, merge_model_settings
29
29
  from .tools import RunContext, Tool, ToolDefinition, ToolsPrepareFunc
30
30
 
@@ -64,12 +64,14 @@ class GraphAgentState:
64
64
  retries: int
65
65
  run_step: int
66
66
 
67
- def increment_retries(self, max_result_retries: int) -> None:
67
+ def increment_retries(self, max_result_retries: int, error: Exception | None = None) -> None:
68
68
  self.retries += 1
69
69
  if self.retries > max_result_retries:
70
- raise exceptions.UnexpectedModelBehavior(
71
- f'Exceeded maximum retries ({max_result_retries}) for result validation'
72
- )
70
+ message = f'Exceeded maximum retries ({max_result_retries}) for result validation'
71
+ if error:
72
+ raise exceptions.UnexpectedModelBehavior(message) from error
73
+ else:
74
+ raise exceptions.UnexpectedModelBehavior(message)
73
75
 
74
76
 
75
77
  @dataclasses.dataclass
@@ -264,7 +266,7 @@ async def _prepare_request_parameters(
264
266
  output_schema = ctx.deps.output_schema
265
267
  return models.ModelRequestParameters(
266
268
  function_tools=function_tool_defs,
267
- allow_text_output=allow_text_output(output_schema),
269
+ allow_text_output=_output.allow_text_output(output_schema),
268
270
  output_tools=output_schema.tool_defs() if output_schema is not None else [],
269
271
  )
270
272
 
@@ -450,7 +452,7 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
450
452
  # when the model has already returned text along side tool calls
451
453
  # in this scenario, if text responses are allowed, we return text from the most recent model
452
454
  # response, if any
453
- if allow_text_output(ctx.deps.output_schema):
455
+ if _output.allow_text_output(ctx.deps.output_schema):
454
456
  for message in reversed(ctx.state.message_history):
455
457
  if isinstance(message, _messages.ModelResponse):
456
458
  last_texts = [p.content for p in message.parts if isinstance(p, _messages.TextPart)]
@@ -471,6 +473,7 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
471
473
  tool_calls: list[_messages.ToolCallPart],
472
474
  ) -> AsyncIterator[_messages.HandleResponseEvent]:
473
475
  output_schema = ctx.deps.output_schema
476
+ run_context = build_run_context(ctx)
474
477
 
475
478
  # first, look for the output tool call
476
479
  final_result: result.FinalResult[NodeRunEndT] | None = None
@@ -478,12 +481,12 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
478
481
  if output_schema is not None:
479
482
  for call, output_tool in output_schema.find_tool(tool_calls):
480
483
  try:
481
- result_data = output_tool.validate(call)
484
+ result_data = await output_tool.process(call, run_context)
482
485
  result_data = await _validate_output(result_data, ctx, call)
483
486
  except _output.ToolRetryError as e:
484
487
  # TODO: Should only increment retry stuff once per node execution, not for each tool call
485
488
  # Also, should increment the tool-specific retry count rather than the run retry count
486
- ctx.state.increment_retries(ctx.deps.max_result_retries)
489
+ ctx.state.increment_retries(ctx.deps.max_result_retries, e)
487
490
  parts.append(e.tool_retry)
488
491
  else:
489
492
  final_result = result.FinalResult(result_data, call.tool_name, call.tool_call_id)
@@ -505,7 +508,6 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
505
508
  else:
506
509
  if tool_responses:
507
510
  parts.extend(tool_responses)
508
- run_context = build_run_context(ctx)
509
511
  instructions = await ctx.deps.get_instructions(run_context)
510
512
  self._next_node = ModelRequestNode[DepsT, NodeRunEndT](
511
513
  _messages.ModelRequest(parts=parts, instructions=instructions)
@@ -533,27 +535,22 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
533
535
  output_schema = ctx.deps.output_schema
534
536
 
535
537
  text = '\n\n'.join(texts)
536
- if allow_text_output(output_schema):
537
- # The following cast is safe because we know `str` is an allowed result type
538
- result_data_input = cast(NodeRunEndT, text)
539
- try:
540
- result_data = await _validate_output(result_data_input, ctx, None)
541
- except _output.ToolRetryError as e:
542
- ctx.state.increment_retries(ctx.deps.max_result_retries)
543
- return ModelRequestNode[DepsT, NodeRunEndT](_messages.ModelRequest(parts=[e.tool_retry]))
538
+ try:
539
+ if _output.allow_text_output(output_schema):
540
+ # The following cast is safe because we know `str` is an allowed result type
541
+ result_data = cast(NodeRunEndT, text)
544
542
  else:
545
- return self._handle_final_result(ctx, result.FinalResult(result_data, None, None), [])
546
- else:
547
- ctx.state.increment_retries(ctx.deps.max_result_retries)
548
- return ModelRequestNode[DepsT, NodeRunEndT](
549
- _messages.ModelRequest(
550
- parts=[
551
- _messages.RetryPromptPart(
552
- content='Plain text responses are not permitted, please include your response in a tool call',
553
- )
554
- ]
543
+ m = _messages.RetryPromptPart(
544
+ content='Plain text responses are not permitted, please include your response in a tool call',
555
545
  )
556
- )
546
+ raise _output.ToolRetryError(m)
547
+
548
+ result_data = await _validate_output(result_data, ctx, None)
549
+ except _output.ToolRetryError as e:
550
+ ctx.state.increment_retries(ctx.deps.max_result_retries, e)
551
+ return ModelRequestNode[DepsT, NodeRunEndT](_messages.ModelRequest(parts=[e.tool_retry]))
552
+ else:
553
+ return self._handle_final_result(ctx, result.FinalResult(result_data, None, None), [])
557
554
 
558
555
 
559
556
  def build_run_context(ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, Any]]) -> RunContext[DepsT]:
@@ -795,11 +792,6 @@ async def _validate_output(
795
792
  return result_data
796
793
 
797
794
 
798
- def allow_text_output(output_schema: _output.OutputSchema[Any] | None) -> bool:
799
- """Check if the result schema allows text results."""
800
- return output_schema is None or output_schema.allow_text_output
801
-
802
-
803
795
  @dataclasses.dataclass
804
796
  class _RunMessages:
805
797
  messages: list[_messages.ModelMessage]
@@ -849,7 +841,9 @@ def get_captured_run_messages() -> _RunMessages:
849
841
 
850
842
 
851
843
  def build_agent_graph(
852
- name: str | None, deps_type: type[DepsT], output_type: type[OutputT] | ToolOutput[OutputT]
844
+ name: str | None,
845
+ deps_type: type[DepsT],
846
+ output_type: _output.OutputType[OutputT],
853
847
  ) -> Graph[GraphAgentState, GraphAgentDeps[DepsT, result.FinalResult[OutputT]], result.FinalResult[OutputT]]:
854
848
  """Build the execution [Graph][pydantic_graph.Graph] for a given agent."""
855
849
  nodes = (
@@ -5,6 +5,9 @@ This module has to use numerous internal Pydantic APIs and is therefore brittle
5
5
 
6
6
  from __future__ import annotations as _annotations
7
7
 
8
+ import inspect
9
+ from collections.abc import Awaitable
10
+ from dataclasses import dataclass
8
11
  from inspect import Parameter, signature
9
12
  from typing import TYPE_CHECKING, Any, Callable, cast
10
13
 
@@ -15,10 +18,12 @@ from pydantic.fields import FieldInfo
15
18
  from pydantic.json_schema import GenerateJsonSchema
16
19
  from pydantic.plugin._schema_validator import create_schema_validator
17
20
  from pydantic_core import SchemaValidator, core_schema
18
- from typing_extensions import TypedDict, get_origin
21
+ from typing_extensions import get_origin
22
+
23
+ from pydantic_ai.tools import RunContext
19
24
 
20
25
  from ._griffe import doc_descriptions
21
- from ._utils import check_object_json_schema, is_model_like
26
+ from ._utils import check_object_json_schema, is_model_like, run_in_executor
22
27
 
23
28
  if TYPE_CHECKING:
24
29
  from .tools import DocstringFormat, ObjectJsonSchema
@@ -27,24 +32,53 @@ if TYPE_CHECKING:
27
32
  __all__ = ('function_schema',)
28
33
 
29
34
 
30
- class FunctionSchema(TypedDict):
35
+ @dataclass
36
+ class FunctionSchema:
31
37
  """Internal information about a function schema."""
32
38
 
39
+ function: Callable[..., Any]
33
40
  description: str
34
41
  validator: SchemaValidator
35
42
  json_schema: ObjectJsonSchema
36
43
  # if not None, the function takes a single by that name (besides potentially `info`)
44
+ takes_ctx: bool
45
+ is_async: bool
37
46
  single_arg_name: str | None
38
47
  positional_fields: list[str]
39
48
  var_positional_field: str | None
40
49
 
50
+ async def call(self, args_dict: dict[str, Any], ctx: RunContext[Any]) -> Any:
51
+ args, kwargs = self._call_args(args_dict, ctx)
52
+ if self.is_async:
53
+ function = cast(Callable[[Any], Awaitable[str]], self.function)
54
+ return await function(*args, **kwargs)
55
+ else:
56
+ function = cast(Callable[[Any], str], self.function)
57
+ return await run_in_executor(function, *args, **kwargs)
58
+
59
+ def _call_args(
60
+ self,
61
+ args_dict: dict[str, Any],
62
+ ctx: RunContext[Any],
63
+ ) -> tuple[list[Any], dict[str, Any]]:
64
+ if self.single_arg_name:
65
+ args_dict = {self.single_arg_name: args_dict}
66
+
67
+ args = [ctx] if self.takes_ctx else []
68
+ for positional_field in self.positional_fields:
69
+ args.append(args_dict.pop(positional_field)) # pragma: no cover
70
+ if self.var_positional_field:
71
+ args.extend(args_dict.pop(self.var_positional_field))
72
+
73
+ return args, args_dict
74
+
41
75
 
42
76
  def function_schema( # noqa: C901
43
77
  function: Callable[..., Any],
44
- takes_ctx: bool,
45
- docstring_format: DocstringFormat,
46
- require_parameter_descriptions: bool,
47
78
  schema_generator: type[GenerateJsonSchema],
79
+ takes_ctx: bool | None = None,
80
+ docstring_format: DocstringFormat = 'auto',
81
+ require_parameter_descriptions: bool = False,
48
82
  ) -> FunctionSchema:
49
83
  """Build a Pydantic validator and JSON schema from a tool function.
50
84
 
@@ -58,6 +92,9 @@ def function_schema( # noqa: C901
58
92
  Returns:
59
93
  A `FunctionSchema` instance.
60
94
  """
95
+ if takes_ctx is None:
96
+ takes_ctx = _takes_ctx(function)
97
+
61
98
  config = ConfigDict(title=function.__name__, use_attribute_docstrings=True)
62
99
  config_wrapper = ConfigWrapper(config)
63
100
  gen_schema = _generate_schema.GenerateSchema(config_wrapper)
@@ -176,10 +213,13 @@ def function_schema( # noqa: C901
176
213
  single_arg_name=single_arg_name,
177
214
  positional_fields=positional_fields,
178
215
  var_positional_field=var_positional_field,
216
+ takes_ctx=takes_ctx,
217
+ is_async=inspect.iscoroutinefunction(function),
218
+ function=function,
179
219
  )
180
220
 
181
221
 
182
- def takes_ctx(function: Callable[..., Any]) -> bool:
222
+ def _takes_ctx(function: Callable[..., Any]) -> bool:
183
223
  """Check if a function takes a `RunContext` first argument.
184
224
 
185
225
  Args:
@@ -196,7 +236,7 @@ def takes_ctx(function: Callable[..., Any]) -> bool:
196
236
  else:
197
237
  type_hints = _typing_extra.get_function_type_hints(function)
198
238
  annotation = type_hints[first_param_name]
199
- return annotation is not sig.empty and _is_call_ctx(annotation)
239
+ return True is not sig.empty and _is_call_ctx(annotation)
200
240
 
201
241
 
202
242
  def _build_schema(