mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: added HostedFileContent and HostedVectorStoreContent (#379)
* added HostedFileContent and HostedVectorStoreContent * added convenience functions for hostedcodeinterpretertools * fix docstrings * udpated docstring * clarified parsing logic * updated type names * updated test * and vector stores
This commit is contained in:
committed by
GitHub
Unverified
parent
82d39bc1f7
commit
bbc07931c1
@@ -4,7 +4,7 @@ import inspect
|
||||
from collections.abc import Awaitable, Callable
|
||||
from functools import wraps
|
||||
from time import perf_counter
|
||||
from typing import Annotated, Any, Generic, Protocol, TypeVar, get_args, get_origin, runtime_checkable
|
||||
from typing import TYPE_CHECKING, Annotated, Any, Generic, Protocol, TypeVar, get_args, get_origin, runtime_checkable
|
||||
|
||||
from opentelemetry import metrics, trace
|
||||
from pydantic import BaseModel, Field, create_model
|
||||
@@ -12,6 +12,9 @@ from pydantic import BaseModel, Field, create_model
|
||||
from ._logging import get_logger
|
||||
from .telemetry import GenAIAttributes, start_as_current_span
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._types import AIContents
|
||||
|
||||
tracer: trace.Tracer = trace.get_tracer("agent_framework")
|
||||
meter: metrics.Meter = metrics.get_meter_provider().get_meter("agent_framework")
|
||||
logger = get_logger()
|
||||
@@ -216,6 +219,45 @@ def ai_function(
|
||||
return decorator(func) if func else decorator # type: ignore[reportReturnType, return-value]
|
||||
|
||||
|
||||
def _parse_inputs(
|
||||
inputs: "AIContents | dict[str, Any] | str | list[AIContents | dict[str, Any] | str] | None",
|
||||
) -> list["AIContents"]:
|
||||
"""Parse the inputs for a tool, ensuring they are of type AIContents."""
|
||||
if inputs is None:
|
||||
return []
|
||||
|
||||
from ._types import AIContent, DataContent, HostedFileContent, HostedVectorStoreContent, UriContent
|
||||
|
||||
parsed_inputs: list["AIContents"] = []
|
||||
if not isinstance(inputs, list):
|
||||
inputs = [inputs]
|
||||
for input_item in inputs:
|
||||
if isinstance(input_item, str):
|
||||
# If it's a string, we assume it's a URI or similar identifier.
|
||||
# Convert it to a UriContent or similar type as needed.
|
||||
parsed_inputs.append(UriContent(uri=input_item, media_type="text/plain"))
|
||||
elif isinstance(input_item, dict):
|
||||
# If it's a dict, we assume it contains properties for a specific content type.
|
||||
# we check if the required keys are present to determine the type.
|
||||
if "uri" in input_item:
|
||||
parsed_inputs.append(
|
||||
UriContent(**input_item) if "media_type" in input_item else DataContent(**input_item)
|
||||
)
|
||||
elif "file_id" in input_item:
|
||||
parsed_inputs.append(HostedFileContent(**input_item))
|
||||
elif "vector_store_id" in input_item:
|
||||
parsed_inputs.append(HostedVectorStoreContent(**input_item))
|
||||
elif "data" in input_item:
|
||||
parsed_inputs.append(DataContent(**input_item))
|
||||
else:
|
||||
raise ValueError(f"Unsupported input type: {input_item}")
|
||||
elif isinstance(input_item, AIContent):
|
||||
parsed_inputs.append(input_item)
|
||||
else:
|
||||
raise TypeError(f"Unsupported input type: {type(input_item).__name__}. Expected AIContents or dict.")
|
||||
return parsed_inputs
|
||||
|
||||
|
||||
class HostedCodeInterpreterTool(AITool):
|
||||
"""Represents a hosted tool that can be specified to an AI service to enable it to execute generated code.
|
||||
|
||||
@@ -226,6 +268,7 @@ class HostedCodeInterpreterTool(AITool):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "code_interpreter",
|
||||
inputs: "AIContents | dict[str, Any] | str | list[AIContents | dict[str, Any] | str] | None" = None,
|
||||
description: str | None = None,
|
||||
additional_properties: dict[str, Any] | None = None,
|
||||
):
|
||||
@@ -233,10 +276,19 @@ class HostedCodeInterpreterTool(AITool):
|
||||
|
||||
Args:
|
||||
name: The name of the tool. Defaults to "code_interpreter".
|
||||
inputs: A list of contents that the tool can accept as input. Defaults to None.
|
||||
This should mostly be HostedFileContent or HostedVectorStoreContent.
|
||||
Can also be DataContent, depending on the service used.
|
||||
When supplying a list, it can contain:
|
||||
- AIContents instances
|
||||
- dicts with properties for AIContents (e.g., {"uri": "http://example.com", "media_type": "text/html"})
|
||||
- strings (which will be converted to UriContent with media_type "text/plain").
|
||||
If None, defaults to an empty list.
|
||||
description: A description of the tool.
|
||||
additional_properties: Additional properties associated with the tool, specific to the service used.
|
||||
"""
|
||||
self.name = name
|
||||
self.inputs = _parse_inputs(inputs)
|
||||
self.description = description
|
||||
self.additional_properties = additional_properties
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ __all__ = [
|
||||
"FunctionCallContent",
|
||||
"FunctionResultContent",
|
||||
"GeneratedEmbeddings",
|
||||
"HostedFileContent",
|
||||
"HostedVectorStoreContent",
|
||||
"SpeechToTextOptions",
|
||||
"StructuredResponse",
|
||||
"TextContent",
|
||||
@@ -1036,6 +1038,68 @@ class UsageContent(AIContent):
|
||||
)
|
||||
|
||||
|
||||
class HostedFileContent(AIContent):
|
||||
"""Represents a hosted file content.
|
||||
|
||||
Attributes:
|
||||
file_id: The identifier of the hosted file.
|
||||
type: The type of content, which is always "hosted_file" for this class.
|
||||
additional_properties: Optional additional properties associated with the content.
|
||||
raw_representation: Optional raw representation of the content.
|
||||
|
||||
"""
|
||||
|
||||
type: Literal["hosted_file"] = "hosted_file" # type: ignore[assignment]
|
||||
file_id: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
*,
|
||||
additional_properties: dict[str, Any] | None = None,
|
||||
raw_representation: Any | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Initializes a HostedFileContent instance."""
|
||||
super().__init__(
|
||||
file_id=file_id, # type: ignore[reportCallIssue]
|
||||
additional_properties=additional_properties,
|
||||
raw_representation=raw_representation,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
class HostedVectorStoreContent(AIContent):
|
||||
"""Represents a hosted vector store content.
|
||||
|
||||
Attributes:
|
||||
vector_store_id: The identifier of the hosted vector store.
|
||||
type: The type of content, which is always "hosted_vector_store" for this class.
|
||||
additional_properties: Optional additional properties associated with the content.
|
||||
raw_representation: Optional raw representation of the content.
|
||||
|
||||
"""
|
||||
|
||||
type: Literal["hosted_vector_store"] = "hosted_vector_store" # type: ignore[assignment]
|
||||
vector_store_id: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vector_store_id: str,
|
||||
*,
|
||||
additional_properties: dict[str, Any] | None = None,
|
||||
raw_representation: Any | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Initializes a HostedVectorStoreContent instance."""
|
||||
super().__init__(
|
||||
vector_store_id=vector_store_id, # type: ignore[reportCallIssue]
|
||||
additional_properties=additional_properties,
|
||||
raw_representation=raw_representation,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
AIContents = Annotated[
|
||||
TextContent
|
||||
| DataContent
|
||||
@@ -1044,7 +1108,9 @@ AIContents = Annotated[
|
||||
| FunctionCallContent
|
||||
| FunctionResultContent
|
||||
| ErrorContent
|
||||
| UsageContent,
|
||||
| UsageContent
|
||||
| HostedFileContent
|
||||
| HostedVectorStoreContent,
|
||||
Field(discriminator="type"),
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user