Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add tool call id #1085

Merged
merged 13 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/openinference-semantic-conventions/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ packages = ["src/openinference"]

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
testpaths = [
"tests",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ class MessageAttributes:
The JSON string representing the arguments passed to the function
during a function call.
"""
MESSAGE_TOOL_CALL_ID = "message.tool_call_id"
"""
The id of the tool call.
"""


class MessageContentAttributes:
Expand Down Expand Up @@ -270,6 +274,10 @@ class ToolCallAttributes:
Attributes for a tool call
"""

TOOL_CALL_ID = "tool_call.id"
"""
The id of the tool call.
"""
TOOL_CALL_FUNCTION_NAME = "tool_call.function.name"
"""
The name of function that is being called during a tool call.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
from collections import defaultdict
from typing import Any, DefaultDict, Dict, Mapping, Type

from openinference.semconv.resource import ResourceAttributes
from openinference.semconv.trace import (
DocumentAttributes,
EmbeddingAttributes,
ImageAttributes,
MessageAttributes,
MessageContentAttributes,
RerankerAttributes,
SpanAttributes,
ToolAttributes,
ToolCallAttributes,
)


class TestSpanAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(SpanAttributes)
assert _nested_dict(attributes) == {
"embedding": {
"embeddings": ...,
"model_name": ...,
},
"input": {
"mime_type": ...,
"value": ...,
},
"llm": {
"function_call": ...,
"input_messages": ...,
"invocation_parameters": ...,
"model_name": ...,
"output_messages": ...,
"prompt_template": {
"template": ...,
"variables": ...,
"version": ...,
},
"prompts": ...,
"provider": ...,
"system": ...,
"token_count": {
"completion": ...,
"prompt": ...,
"total": ...,
},
"tools": ...,
},
"metadata": ...,
"openinference": {
"span": {
"kind": ...,
}
},
"output": {
"mime_type": ...,
"value": ...,
},
"retrieval": {
"documents": ...,
},
"session": {
"id": ...,
},
"tag": {
"tags": ...,
},
"tool": {
"description": ...,
"name": ...,
"parameters": ...,
},
"user": {
"id": ...,
},
}


class TestMessageAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(MessageAttributes)
assert _nested_dict(attributes) == {
"message": {
"content": ...,
"contents": ...,
"function_call_arguments_json": ...,
"function_call_name": ...,
"name": ...,
"role": ...,
"tool_call_id": ...,
"tool_calls": ...,
}
}


class TestMessageContentAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(MessageContentAttributes)
assert _nested_dict(attributes) == {
"message_content": {
"image": ...,
"text": ...,
"type": ...,
}
}


class TestImageAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(ImageAttributes)
assert _nested_dict(attributes) == {
"image": {
"url": ...,
}
}


class TestDocumentAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(DocumentAttributes)
assert _nested_dict(attributes) == {
"document": {
"content": ...,
"id": ...,
"metadata": ...,
"score": ...,
}
}


class TestRerankerAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(RerankerAttributes)
assert _nested_dict(attributes) == {
"reranker": {
"input_documents": ...,
"model_name": ...,
"output_documents": ...,
"query": ...,
"top_k": ...,
}
}


class TestEmbeddingAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(EmbeddingAttributes)
assert _nested_dict(attributes) == {
"embedding": {
"text": ...,
"vector": ...,
}
}


class TestToolCallAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(ToolCallAttributes)
assert _nested_dict(attributes) == {
"tool_call": {
"function": {
"arguments": ...,
"name": ...,
},
"id": ...,
},
}


class TestToolAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(ToolAttributes)
assert _nested_dict(attributes) == {
"tool": {
"json_schema": ...,
}
}


class TestResourceAttributes:
def test_nesting(self) -> None:
attributes = _flat_dict(ResourceAttributes)
assert _nested_dict(attributes) == {
"openinference": {
"project": {
"name": ...,
}
}
}


def _flat_dict(cls: Type[Any]) -> Dict[str, Any]:
return {v: ... for k, v in cls.__dict__.items() if k.isupper()}


def _nested_dict(
attributes: Mapping[str, Any],
) -> DefaultDict[str, Any]:
nested_attributes = _trie()
for attribute_name, attribute_value in attributes.items():
trie = nested_attributes
keys = attribute_name.split(".")
for key in keys[:-1]:
trie = trie[key]
trie[keys[-1]] = attribute_value
return nested_attributes


def _trie() -> DefaultDict[str, Any]:
return defaultdict(_trie)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from openinference.semconv.trace import (
OpenInferenceLLMProviderValues,
OpenInferenceLLMSystemValues,
OpenInferenceMimeTypeValues,
OpenInferenceSpanKindValues,
)


class TestOpenInferenceSpanKindValues:
def test_values(self) -> None:
assert {e.name: e.value for e in OpenInferenceSpanKindValues} == {
"AGENT": "AGENT",
"CHAIN": "CHAIN",
"EMBEDDING": "EMBEDDING",
"EVALUATOR": "EVALUATOR",
"GUARDRAIL": "GUARDRAIL",
"LLM": "LLM",
"RERANKER": "RERANKER",
"RETRIEVER": "RETRIEVER",
"TOOL": "TOOL",
"UNKNOWN": "UNKNOWN",
}


class TestOpenInferenceMimeTypeValues:
def test_values(self) -> None:
assert {e.name: e.value for e in OpenInferenceMimeTypeValues} == {
"JSON": "application/json",
"TEXT": "text/plain",
}


class TestOpenInferenceLLMSystemValues:
def test_values(self) -> None:
assert {e.name: e.value for e in OpenInferenceLLMSystemValues} == {
"ANTHROPIC": "anthropic",
"COHERE": "cohere",
"MISTRALAI": "mistralai",
"OPENAI": "openai",
"VERTEXAI": "vertexai",
}


class TestOpenInferenceLLMProviderValues:
def test_values(self) -> None:
assert {e.name: e.value for e in OpenInferenceLLMProviderValues} == {
"ANTHROPIC": "anthropic",
"AWS": "aws",
"AZURE": "azure",
"COHERE": "cohere",
"GOOGLE": "google",
"MISTRALAI": "mistralai",
"OPENAI": "openai",
}

This file was deleted.

Loading
Loading